basis
component
The React component can be written in three ways: es6 class syntax. It inherits the React.componentclass to implement components with a full life cycle
import React, { Component } from 'react';
export default class SingleComponent extends Component {
/* Contains some lifecycle functions, inner functions, and variables */
render() {
return (<div>{/ * * /}</div>)}}Copy the code
The second type is stateless components, also known as functional components
const SingleComponent = (props) = > (
<div>{props.value}</div>
);
export default SingleComponent;
Copy the code
A higher-order component is strictly a higher-order function that wraps the above two components
const HighOrderComponent = (WrappedComponent) = > {
class Hoc extends Component {
/* contains some lifecycle functions */
render() {
return (<WrappedComponent {. this.props} / >);
}
}
return Hoc;
}
Copy the code
The principle of higher-order components is to accept a component and return a wrapped component. Some life-cycle functions can be inserted into the returned component to perform corresponding operations. Higher-order components can make the logic of the wrapped component be extended from the outside without interference
Props and state
The react component state is called state, which can be initialized using a simple syntax in es6+ class components
export default class Xxx extends Component {
state = {
name: 'sakura',
}
render() {
const { name } = this.state;
return (<div>{name}</div>); }}Copy the code
State can be assigned to a tag. If you need to update state, you can call this.setState() to pass in an object. After changing state with this method, elements bound to the corresponding value will also trigger rendering, which is simple data binding
You cannot modify state by this.state.name = ‘XXX’, as this would lose the effect of updating state and changing the corresponding element
The setState function is an important and frequently used API in React. It takes at most two parameters. The first parameter is the state object to be modified, and the second parameter is a callback function that will be called automatically after the state update operation is completed. Instead of updating state immediately after calling this.setState, React merges objects returned from several consecutive calls to setState to improve performance. The following code may not produce the desired effect
class SomeButton extends Component {
state = {
value: 1,
}
handleClick = (a)= > {
const { value } = this.state;
this.setState({ value: value + 1 });
this.setState({ value: value + 1 });
this.setState({ value: value + 1 });
this.setState({ value: value + 1 });
}
render() {
const { value } = this.state;
return (<div>
<span>{vlaue}</span>
<button onClick={this.handleClick}>click!</button>
</div>); }}Copy the code
Instead of doing 4 +1 operations on value, React will do a merge of the 4 updates, leaving only one result, something like this
Object.assign({},
{ value: value + 1 },
{ value: value + 1 },
{ value: value + 1});Copy the code
And because setState is asynchronous, you cannot get a new state immediately after the call. If you do, you can only get it by passing the second parameter callback to setState
/* omit some code */
this.setState({
value: 11,}, () => {const { value } = this.state;
console.log(value);
})
Copy the code
Props is an attribute object passed by the parent element to the child element, usually used like this
class Parent extends Component {
/* The parent component holds a value*/ in state
state = {
value: 0}; handleIncrease =(a)= > {
const { value } = this.state;
this.setState({ value: value + 1 });
}
render() {
const { value } = this.state;
// Passes props to the Child, and passes a function for the Child to modify value when it clicks
return (<div>
<Child value={value} increase={this.handleIncrease} />
</div>Const Child = (props) => (const Child = (props) => (<div>
<p>{props.value}</p>
<button onClick={props.increase}>click!</button>
</div>
);
Copy the code
The props is like a pipe through which the state of the parent component flows to the child component. This process is called unidirectional data flow
Changing state and props in React causes components to be re-rendered
Component life cycle
The lifecycle is a set of special functions used to represent components from rendering to unloading and to receive new props and state declarations
- mount
- componentWillMount
- render
- componentDidMount
- update
- componentWillReceiveProps
- shouldComponentUpdate
- componentWillUpdate
- render
- componentDidUpdate
- uninstall
- componentWillUnmount
Mount – componentWillMount
At this stage, the component is ready to render the DOM node. You can do some requests and things like that in this method, but because the component has not been rendered for the first time, you cannot get any DOM nodes
Mount – render
This method returns the dom node that needs to be rendered and does the data binding. You cannot call this.setState to change the state in this method, because setState will trigger a re-rendering, causing the render function to be called again to trigger an infinite loop
Mount – componentDidMount
In this phase, the component is rendered for the first time, and you can retrieve the actual DOM node, do some request operations in this method, or bind events, etc
Update – componentWillReceiveProps
This method is automatically triggered when the component receives new props and state and has not executed render. In this phase, the new props and state can be obtained. In some cases, some operations may need to be performed based on the comparison between the old props and the new props. For example, the popover state of a popover component is stored in the parent component’s state and passed to the props itself
class Dialog extends Component {
componentWillReveiceProps(nextProps) {
const { dialogOpen } = this.props;
if(nextProps.dialogOpen && nextProps.dialogOpen ! == dialogOpen) {/* Pop-ups pop up */}}}Copy the code
Update – shouldComponentUpdate
ShouldComponentUpdate is a very important API. React the components of the update process through above several stages, arrived at this stage need to confirm whether a component rendering again really need according to the new state, confirmed on the basis of whether is the contrast between old and new state change, if there is no change, return false function does not perform at the back of the life cycle, if change the returns true, Continue with the rest of the life cycle, and React returns true by default
So shouldComponentUpdate can be used to optimize performance, you can manually implement shouldComponentUpdate function to compare the state of the difference before and after, so as to prevent unnecessary repeated rendering components
class Demo extends Component {
shouldComponentUpdate(nextProps, nextState) {
return this.props.value !== nextProps.value;
}
}
Copy the code
Value of this.props. Value and nextProps. Value are the same to determine whether the component needs to be re-rendered. The deeper the data nesting is, the deeper the comparison is, the more expensive the react performance is, the more Immutable
Because imMutableJS itself is immutable, it returns a new object if it needs to modify the state, and because it returns a new object after modification, shouldComponentUpdate method just need to compare the object reference is easy to get the result, do not need to do a deep comparison. But using imMutableJS means increasing learning costs, so there are trade-offs to be made
Update – componentWillUpdate
ShouldComponentUpdate this phase is called automatically when the new state is received and shouldComponentUpdate is sure that the component needs to be rerendered but has not yet been rendered. This phase still gets the new props and state and is the last chance to update the state before the component is rerendered
Update – render
Rerender according to the new state
Update – componentDidMount
Re-render
Uninstall – componentWillmount
This is where timers can be cleared and events can be dismissed before components are unloaded
Component communication
In many service scenarios, communication between parent components, parent components, and even sibling components is often involved. Parent components can communicate with each other through props. Child => parent component communication is a common problem for most beginners. Suppose you have a requirement, a child component is a drop-down selection menu, a parent component is a form, and after selecting an item in the menu, you need to pass the value to the parent form component. This is a typical requirement for the child => parent component to pass the value
const list = [ { name: 'sakura', id: 'x0001' }, { name: 'misaka', id: 'x0003' }, { name: 'mikoto', id: 'x0005' }, { name: 'react', id: 'x0002' }, ]; class DropMenu extends Component { handleClick = (id) => { this.props.handleSelect(id); } render() { <MenuWrap> {list.map((v) => ( <Menu key={v.name} onClick={() => this.handleClick(v.id)}>{v.name}</Menu> ))} </MenuWrap> } } class FormLayout extends Component { state = { selected: '', } handleMenuSelected = (id) => { this.setState({ selected: id }); } render() { <div> <MenuWrap handleSelect={this.handleMenuSelected} /> </div> } }Copy the code
In this example, the parent component, FormLayout, passes a function to the child component. The child component’s Menu click calls this function and passes in the value. The parent component receives the value
However, for the more complex components of the same level or even similar to the relationship between uncle and nephew, they can communicate with each other through the way of state promotion. Simply put, if the two components are not nested and there is no parent-child relationship, in this case, they can find the common parent component of their upper layer and store the state in this parent component. Pass the corresponding state and the corresponding callback functions to the two components via props
routing
The most common routing solution in React is the React-router. The react-router has gone through four iterations with major API changes in each version. In this article, we will introduce the latest version of React-router-V4
Basic usage
To use routing, you need to wrap the App with the Router component and pass the history object through props. In the latest version, history is separated into a package and needs to be imported before using it. For the Switch of peer component routes, multiple routes need to be wrapped with the Switch component. Each time the Route changes, only one matching component will be rendered
import ReactDOM from 'react-dom';
import createHistory from 'history/createBrowserHistory';
import { Router } from 'react-router';
import App from './App';
const history = createHistory();
ReactDOM.render(
<Router history={history}>
<App />
</Router>,
element,
);
// App.js
/ /... Omit some code
import {
Switch, Route,
} from 'react-router';
class App extends Component {
render() {
return( <div> <Switch> <Route exact path="/" component={Dashboard} /> <Route path="/about" component={About} /> </Switch> </div> ); }}Copy the code
CodesanBox online example
State management
For single-page application state management, you can first read this article about single-page application data flow solution exploration
The React ecosystem’s state management solution is based on The Flux architecture proposed by Facebook and has several different implementations. The two most popular are
- Mobx
- Redux
Flux
Flux is the application architecture that Facebook uses for building client-side web applications. It complements React’s composable view components by utilizing a unidirectional data flow. It’s more of a pattern rather than a formal framework, and you can start using Flux immediately without a lot of new code.
Flux is a facebook architecture for building Web applications that complements React components by using a one-way data flow supplement. It is a pattern, not a formal framework
First, Flux divides an application into three parts:
- dispatcher
- stores
- views
dispatcher
The Dispatcher is the central hub for managing all data flows in the Flux application. Its function is simply to distribute actions to stores. Each store listens to itself and provides a callback function
Facebook’s official implementation of dispatcher.js
stores
Stores contain the state and logic of the application, similar to the Model in traditional MVC, stores are used to store the state of a specific area scope in the application
A store registers an event with the Dispatcher and provides a callback function that takes action as an argument and distinguishes and interprets actions based on actionType. The corresponding data update function is provided in the Store, and after confirming the update, an event is broadcast for the application to update the view based on the new state
// Facebook officially implements FluxReduceStore usage
import { ReduceStore, Dispatcher } from 'flux';
import Immutable from 'immutable';
const dispatch = new Dispatcher();
class TodoStore extends ReduceStore {
constructor() {
super(dispatch);
}
getInitialState() {
return Immutable.OrderedMap();
}
reduce(state, action) {
switch(action.type) {
case 'ADD_TODO':
return state.set({
id: 1000.text: action.text,
complete: false});default:
returnstate; }}}export default new TodoStore();
Copy the code
views
React provides views that can be combined and freely rerendered. In the React topmost component, it uses some glue code to get the required data from stores and pass the data to its sub-components via props. We can manage the state of any part of the page by controlling the state of the top-level component
The official Facebook implementation has a fluxContainer.js that connects the Store and React components and refreshes the component status update view after the Store updates data. The basic idea is to pass in the Stores and the state and methods required by the component, as well as the component itself, with a higher-order component, and return the component that has injected the state and action methods. The basic usage looks like this
import TodoStore from './TodoStore';
import Container from 'flux';
import TodoActions from './TodoActions';
// There can be multiple stores
const getStores = (a)= > [TodoStore];
const getState = (a)= > ({
/ / state
todos: TodoStore.getState(),
// action
onAdd: TodoActions.addTodo,
});
export default Container.createFunctional(App, getStore, getState);
Copy the code
The CodeSanbox online sample will be supplemented later with the source code parsing of flux’s official implementation
Redux
Redux is another implementation of Flux architecture by Dan Abramov. It continues the ideas of views, Store and dispatch in Flux architecture and makes improvement on this basis by splitting the reduce function in the original store into reducer. And merge multiple stores into one store to make it more convenient for testing
The Evolution of Flux Frameworks
The first change is to have the action creators return the dispatched action.What looked like this:
export function addTodo(text) {
AppDispatcher.dispatch({
type: ActionTypes.ADD_TODO,
text: text
});
}
Copy the code
can look like this instead:
export function addTodo(text) {
return {
type: ActionTypes.ADD_TODO,
text: text
};
}
Copy the code
Stores were split into a single store and multiple reducer
const initialState = { todos: []};export default function TodoStore(state = initialState, action) {
switch (action.type) {
case ActionTypes.ADD_TODO:
return { todos: state.todos.concat([action.text]) };
default:
return state;
}
Copy the code
Redux divides the application into four parts
- views
- action
- reducer
- store
Views can trigger an action, and the Reducer function internally performs operations on the data according to different actions. Finally, a new state is returned, and the Store forms a state tree from all the states returned by the Reducer. Updates to views via subscribed event functions
views
The React component acts as the view layer in the application
action
Action is a simple JavaScript object that contains a Type attribute and the parameters required for the action action. It is recommended to use actionCreator to return an action, which can be passed to the component as state
function singleActionCreator(payload) {
return {
type: 'SINGLE_ACTION',
paylaod,
};
}
Copy the code
reducer
Reducer is a pure function that simply returns corresponding output according to the specified input. The Reducer function should have no side effects and finally needs to return a state object. For multiple reducer functions, combineReducer functions can be combined
function singleReducer(state = initialState, action) {
switch(action.type) {
case 'SINGLE_ACTION':
return { ...state, value: action.paylaod };
default:
returnstate; }}function otherReducer(state = initialState, action) {
switch(action.type) {
case 'OTHER_ACTION':
return { ...state, data: action.data };
default:
returnstate; }}const rootReducer = combineReducer([
singleReducer,
otherReducer,
]);
Copy the code
store
There is only one store in redux. A store can be created by calling createStore and passing it into reducer. This store contains several methods, namely subscribe, Dispatch, getState, and replaceReducer. Subscribe registers a callback function for state updates, dispatch manually triggers an action, getState gets the current state tree, replaceReducer replaces reducer, redux is used in react projects, You have to combine it with React-redux
import { connect } from 'react-redux';
const store = createStore(rootReducer);
// App.js
class App extends Component {
render() {
return (
<div>
test
</div>); }}const mapStateToProps = (state) = > ({
vlaue: state.value,
data: state.data,
});
const mapDispatchToProps = (dispatch) = > ({
singleAction: (a)= > dispatch(singleActionCreator());
});
export default connect(mapStateToProps, mapDispatchToProps)(App);
// index.js
import { Provider } from 'react-redux';
ReactDOM.render(
<Provider store={store}>
<APP />
</Provider>,
element,
);
Copy the code
CodeSanbox online example
Because my technical level is limited, if there is a mistake in the article or careless mistake welcome big brothers to point out
Blog address, update periodically