npm is the package manager for node.js, the server-side JavaScript execution environment. Most React apps load the React library and 3rd party libraries/extensions through npm packages.
If you're new to JavaScript development, or if you've been using older libraries (e.g. jQuery, Backbone), you may not have used npm for client-side app development. While npm was originally intended for use exclusively in node.js server-side code, it's now commonly used for the client-side code too. (Webpack)
npm init –f
npm install –save (npm i -S)
npm install –save-dev (npm i -D)
npm uninstall (npm un)
npm start (npm start -- --env=dev)
npm test (npm t; npm t -- --watch)
Webpack bundles your client-side code (JavaScript, CSS, etc) into a single JavaScript file. Webpack is highly configurable with plugins, allowing you to bundle nearly any kind of asset imaginable.
Webpack is the most common way to bundle a React app during development and for production. If you want more flexibility and power than Facebook's create-react-app, you should learn how to use Webpack and the Babel plugin (for compiling your ES2015/JSX code for browser compatibility)
Webpack is a huge topic, and the official documentation is work-in-progress. You'll likely run into issues and have to search for relevant stack overflow answers and git issues. For now, this is pretty normal, so expect to do some troubleshooting and don't get too discouraged!
npm install webpack –D
npm install webpack-dev-server –D
module.exports = env => {
return {
entry: “index.js”,
output: {
filename: “bundle.js”
},
plugins: [
CommonsChunkPlugin, ExtractTextPlugin,
CleanWebpackPlugin, HtmlWebpackPlugin, DefinePlugin
]
};
};
Babel is a highly configurable compiler that lets you use experimental JavaScript features and extensions, compiling down into older JavaScript versions that can be supported on a wider range of platforms. Of course, if a native platform doesn't support an ES2015 feature like Promise(), Babel won't fully be able to help -- but it can in many cases "polyfill" missing APIs to provide this functionality.
Babel enables debugging of the original source code by including source maps with the compiled JavaScript. JavaScript interpreters will run the compiled code, but map it to the source code in the debugger so that you can debug the source code instead of the (generally quite ugly) compiled output.
Babel comes in two parts: the core, and plugins. Each individual language feature that Babel can compile, such as ES2015 classes, has a separate plugin. Collections of plugins are grouped into presets, so that you don't have to install hundreds of individual dependencies.
Babel groups experimental language features into presets called stages, with stage-0 being the most experimental (i.e. these may not make it into the official language spec) and stage-3 (these features aren't going anywhere).
npm install --save-dev babel-loader babel-core babel-preset-react babel-preset-env babel-preset-stage-1 babel-plugin-transform-runtime
npm install --save babel-runtime
module.exports = env => {
return {
entry: './index.js',
output: {
filename: 'bundle.js',
},
module: {
rules: [
{
test: /.js$/,
exclude: /node_modules/,
use: [
{
loader: 'babel-loader',
options: {
cacheDirectory: true,
},
},
],
},
],
},
}
}
{
"presets": [
["env", {"modules": false}],
"stage-1",
"react"
],
"plugins": [
"transform-runtime"
]
}
React comes in two parts, React and ReactDOM. React includes the core component APIs and rendering logic. ReactDOM contains the necessary APIs to render to the browser DOM.
npm install --save react react-dom
import React, { Component } from 'react'
import ReactDOM from 'react-dom'
const styles = {
app: {
paddingTop: 40,
textAlign: 'center',
},
}
class App extends Component {
render() {
return (
<div style={styles.app}>
<h1>Welcome to React!</h1>
<p>I'm a paragraph</p>
</div>
)
}
}
const root = document.querySelector('#app')
ReactDOM.render(<App />, root)
Eslint is a pluggable linting utility for Javascript.
Linting is a good coding practice whose goal is to detect possible errors and suspicious code, optimizing readability and maintainability, and enhancing your development with best practices for any given development paradigm (React, functional programming)
http://kangax.github.io/compat-table/es6/
Bound instance method no more bind!
Object spread const a={foo:"bar"}; let b ={{joe:"test"}, …a}
Object rest let {a, ...rest}
Async and await
Class and property decorators
Observable
Facebook provides a command-line utility called create-react-app which automatically sets up a new React project with a sensible default project structure and feature set. This is the best way to get started as a beginner.
You'll likely outgrow this option pretty quickly as you get a better grasp of React and want to customize your stack. Fortunately, create-react-app offers an eject option to export your app, so you're not locked in.
ReactDOM API
ReactDOM.render()
REACT API
React.Component
React.PureComponent
PropTypes
Children
this.props
this.state
this.setState({object:value}, callback)
defaultProps
this.setState({},()=>{console.log("callback")});
//receives a callback function
this.setState({state.quantity+1});
this.setState({state.quantity+1});
//updates once
this.setState((prevState) => ({counter: prevState.quantity + 1}));
this.setState((prevState) => ({counter: prevState.quantity + 1}));
//using and updater function, updates twice
this.setState((prevState, props) => {
return {counter: prevState.counter + props.step};
});
// the updater function receives a second parameter, with the current props
class MyComponent extends React.Component{
constructor(props){}
componentWillMount(){}
render(){}
componentDidMount(){}
componentWillReceiveProps(nextProps){}
shouldComponentUpdate(nextProps, nextState){}
componentWillUpdate(nextProps, nextState){}
componentDidUpdate(prepProps, prevState){}
componentWillUnmount(){}
}
import React, { Component } from 'react'
import { render } from 'react-dom'
const randomColor = () => '#' + Math.random().toString(16).substr(-6);
class Card extends Component {
render() {
const style = {
padding: 20,
textAlign: 'center',
color: 'white',
backgroundColor: this.props.color,
}
return (
<div style={style}>
{this.props.children}
</div>
)
}
}
class App extends Component {
state = {
color: 'skyblue'
}
randomizeColor = () => this.setState({color: randomColor()})
render() {
const {color} = this.state
const style = {
padding: 20,
}
return (
<div style={style}>
<Card color={color}>
<input type={'button'} value={'Randomize Color'}
onClick={this.randomizeColor}
/>
</Card>
</div>
)
}
}
render(<App />, document.querySelector('#app'))
import React, { Component } from 'react'
import { render } from 'react-dom'
import styled from 'styled-components'
const randomColor = () => '#' + Math.random().toString(16).substr(-6);
const Card = styled.div`
padding: 20px;
text-align: center;
color: white;
background-color: ${props => props.color};
const Container = styled.div`
padding: 20px;
class App extends Component {
state = {color: 'skyblue'};
randomizeColor = () => this.setState({color: randomColor()});
render() {
const {color} = this.state;
return (
<Container>
<Card color={color}>
<input type={'button'} value={'Randomize Color'}
onClick={this.randomizeColor}
/>
</Card>
</Container>
)
}
};
render(<App />, document.querySelector('#app'))
Performance
onClick={()=>this.setState({count:count+1})}
Input handling (controlled vs uncontrolled inputs)
Conditional rendering
if() == {myvar && <Component/>}
Ternary operator
{listHasItems ? <ComponentList/> : <EmptyList/>}
Keys
articleList.map((article, index)=>(<li key={index}>{article}</li>))
Refs
Smart/Container Components & Presentational/Dumb Components
Redux is a predictable state container for JavaScript apps.
Describe application state as plain objects and arrays.
Describe changes in the system as plain objects.
Describe the logic for handling changes as pure functions.
Redux is that is an alternative way to manage state in a React.
class NormalReact extends React.Component {
constructor() {
super();
this.state = {message: "This is a local state."};
}
componentDidMount(){
this.setState({message:"state is changed when component is mounted"});
}
}
Describe application state as plain objects and arrays.
Describe changes in the system as plain objects.
Describe the logic for handling changes as pure functions.
Single source of truth
The state of your whole application is stored in an object tree within a single store.
State is read-only
The only way to change the state is to emit an action, an object describing what happened.
Changes are made with pure functions
To specify how the state tree is transformed by actions, you write pure reducers.
// State
{
todos: [{
text: 'Eat food',
completed: true
}, {
text: 'Exercise',
completed: false
}],
visibilityFilter: 'SHOW_COMPLETED'
}
// Actions
const addTodoType = { type: 'ADD_TODO', text: 'Go to swimming pool' };
const toggleTodo = { type: 'TOGGLE_TODO', index: 1 };
const changeVisibility = { type: 'SET_VISIBILITY_FILTER', filter: 'SHOW_ALL' };
//Action creator
function addTodo(text){
return {
type:"ADD_TODO",
text // same as text:text
};
}
function visibilityFilter(state = 'SHOW_ALL', action) {
if (action.type === 'SET_VISIBILITY_FILTER') {
return action.filter
} else {
return state
}
}
function todos(state = [], action) {
switch (action.type) {
case 'ADD_TODO':
return state.concat([{ text: action.text, completed: false }])
case 'TOGGLE_TODO':
return state.map(
(todo, index) =>
action.index === index
? { text: todo.text, completed: !todo.completed }
: todo
)
default:
return state
}
}
An action is a plain JavaScript object that describes what happened. Actions must have a type property that indicates the type of action being performed. Types should typically be defined as string constants.
Actions are payloads of information that send data from your application to your store. They are the only source of information for the store. You send them to the store using store.dispatch()
Action creators are exactly that—functions that create actions. It's easy to conflate the terms “action” and “action creator,” so do your best to use the proper term.
In Redux action creators simply return an action:
export default function addTodo(text) {
return {
type: ADD_TODO,
text // same as text:text
}
}
const text = "learn Redux";
store.dispatch(addTodo(text));
//within a container
dispatch(addTodo(text));
Then, we pass the action creator’s result to the store’s dispatch method:
A reducer is a function that takes state and action as arguments and returns the next state of the app. It would be hard to write such a function for a big app, so we write smaller functions managing parts of the state
Holds the application state;
Allows access to state via getState();
Allows state to be updated via dispatch(action);
Registers listeners via subscribe(listener);
Handles unregistering of listeners via the function returned by the function subscribe (listener).
In Redux, the data flow is unidirectional:
Dispatch an action to tell the store what happened
store.dispatch(action);
The Redux store calls the reducer function you gave it.
let nextState = reducer(previousState,action);
(Optional) the root reducer may combine the output of multiple reducers into a single state tree.
combineReducers({reducerA, reducerB, ...reducerN})
Redux saves the complete state tree at the store
the updated state is available by store.getState();
Installing React Redux
npm install --save react-redux
Presentational & Container Components
Presentational Components
Container Components
Connect(mapStateToProps, mapDispatchToProps) function
mapStateToProps
mapDispatchToProps
Passing the Store
import Component from “url/to/presentational/component”;
import * as actions from "url/to/actions";
const mapStateToProps = state => ({
twigs: state.twigs,
activeTwigs: getTwigsByStatus(state.twigs, "Active")
});
const mapDispatchToProps = dispatch => ({
load: (id) => dispatch(actions.load()),
save: (data) => dispatch(actions.save(data)),
error:()=> dispatch(actions.error())
});
export default connect(mapStateToProps, mapDispatchToProps)(Component);
The Redux’s provider is a savvy function that allows us to magically (vía context) make the store accessible to every connected app’s container. This saves us the tedious task of passing the store down as a prop to any component within our app.
import React from 'react'
import { render } from 'react-dom'
import { Provider } from 'react-redux'
import { createStore } from 'redux'
import todoApp from './reducers'
import App from './components/App'
let store = createStore(todoApp)
render(
<Provider store={store}>
<App />
</Provider>,
document.getElementById('root')
)
Every Redux action needs to be a plain object, a pure function, so then we create a function that generates the desired action payload.
Redux Thunk is a middleware that checks when an action creator returns a function, so it can execute it internally. This function isn’t required to be pure, allowing side effects, like executing asynchronous API calls and also dispatching other actions.
import thunkMiddleware from 'redux-thunk'
const store = createStore(
rootReducer,
applyMiddleware(
thunkMiddleware,
loggerMiddleware
)
)
function loadTask(id) {
return dispatch => {
dispatch(clearTasks());
return axios
.get(`https://www.example-api.com/${id}`)
.then(json => dispatch(receiveTasks(id))
.catch(error=> dispatch(loadError(error))));
}
}
A Redux middleware is a code you put between dispatching an action, and the moment it reaches the reducer. People use Redux middleware for logging, crash reporting, talking to an asynchronous API, routing, and more.
const logger = store => next => action => {
console.log('dispatching', action);
let result = next(action);
console.log('next state', store.getState());
return result;
}
function logger(store) {
return function (next) {
return function (action) {
console.log('dispatching', action);
var result = next(action);
console.log('next state', store.getState());
return result;
};
};
};
Redux Logger
const thunk = store => next => action => {
if (typeof action.then !== 'function') {
return next(action);
}
return Promise
.resolve(action)
.then(store.dispatch);
}
function thunk(store) {
return function (next) {
return function (action) {
if (typeof action.then !== 'function') {
return next(action);
}
return Promise
.resolve(action)
.then(store.dispatch);
};
};
};
Redux-thunk
Jest is a test runner created by Facebook, featuring a fast setup environment with instant feedback with built-in coverage and Snapshot testing.
Jest parallelizes test runs across workers to maximize performance.
Is built on top of Jasmine, so you can expect the same assertion features.
Enzyme is an Airbnb javascript testing utility for React that makes easy to assert, manipulate, and traverse your React's component output
Shallow rendering is used to constrain yourself to test a component as a unit, and to ensure that your tests aren't indirectly asserting on the behavior of child components.
class Foo extends React.Component{
render(){
return(<div><Bar/></div>);
};
}
import {shallow} from "enzyme";
describe('<MyComponent />', () => {
it('should render the <Foo /> component', () => {
const wrapper = shallow(<MyComponent />);
expect(wrapper.find(Foo).length).toBe(1);
expect(wrapper.find("div").length).toBe(1);
});
});
Full DOM rendering is used for cases where you need to fully interact with your DOM APIs, using lifecycles like componentDidMount, etc.
You must also configure a browser environment, like jsdom, which is a headless browser implemented in js.
class Foo extends React.Component{
render(){
return(<div><Bar/></div>);
};
}
class Bar extends React.Component{
render(){
return(<div><p>Bar</p></div>);
};
}
import {shallow} from "enzyme";
describe('<MyComponent />', () => {
it('calls componentDidMount', () => {
sinon.spy(Foo.prototype, 'componentDidMount');
const wrapper = mount(<Foo />);
expect(Foo.prototype.componentDidMount.calledOnce).to.equal(true);
expect(wrapper.find("p").text()).toContain("Bar");
});
});
Enzyme offers support to traverse a React component via selectors. The can be a:
//CSS selectors
wrapper.find('.foo');
wrapper.find('div');
wrapper.find('#foo-bar');
//React Component
import Foo from "./Foo";
wrapper.find(Foo);
//Component¡s display name
wrapper.find("Foo");
//Obejct Property Selector
wrapper.find({ foo: 3 });
wrapper.find({ bar: false });
GFT Group
Anyul Rivas
Technical Lead
Av. Alcalde Barnils, 69-71.
08174 Sant Cugat, Spain.
T +34 711 620 420
anyul.rivas@gft.com