React In-Depth Series 3: Props and State

Text: Xu Chao, author of "The Road to Advanced React"

Authorized to publish, reprint please indicate the author and source


React In-Depth Series 3: Props and State

React in-depth series, in-depth explanation of the key concepts, features and patterns in React, aims to help you deepen your understanding of React, and use React more flexibly in your projects.

The core idea of ​​React is the idea of ​​componentization, and the definition of React components can be described by the following formula:

UI = Component(props, state)

The component calculates the UI of the corresponding interface according to the two parameters of props and state. It can be seen that props and state are two important data sources for components.

This article is not an introduction to the basic usage of props and state, but an attempt to explain props and state at a deeper level and summarize the precautions when using them.

The nature of props and states

In a word, props is the external interface of the component, and state is the internal interface of the component. Components can reference other components, and the references between components form a tree-like structure (component tree). If the lower-level component needs to use the data or methods of the upper-level component, the upper-level component can be passed through the props property of the lower-level component. Therefore, props It is the external interface of the component. In addition to using the data passed by the upper-level component, the component may also need to maintain and manage data itself, which is the interface state within the component. According to the external interface props and the internal interface state, the component calculates the UI of the corresponding interface.

The props and state of the component are directly related to the final UI rendered by the component. The main difference between the two is: state is variable, and is a set of states maintained within the component to reflect changes in the component's UI; while props is a read-only property of the component, and props cannot be directly modified inside the component. If you want to modify props , which can only be modified in the upper-level component of this component. In the scenario where the component state is moved up , the parent component passes the required state to the child component through the child component's props.

How to define State

Defining an appropriate state is the first step in properly creating a component. The state must be able to represent the complete set of states presented by the UI of a component , that is, any change in the UI corresponding to the component can be reflected from the changes in the state; at the same time, the state must also represent the minimum set of states presented by the UI of a component , that is, in the state All of the states are used to reflect changes in the component's UI, without any redundant states, and no intermediate states calculated from other states.

Whether a variable used in the component should be used as the component state can be judged by the following four criteria:

  1. Is this variable obtained from the parent component via props? If it is, then it is not a state.
  2. Does this variable persist throughout the lifetime of the component? If it is, then it is not a state.
  3. Can this variable be computed from existing data in state or props? If it is, then it is not a state.
  4. Is this variable used in the render method of the component? If not , then it's not a state. In this case, this variable is more suitable to be defined as a common property of the component (component properties other than props and state), such as the timer used in the component, it should be directly defined as this.timer instead of this.state .timer.

It's important to keep in mind that not all variables used in a component are the state of the component! When there are multiple components that depend on the same state, the general practice is to move the state up and put this state in the common parent component of these components.

How to Correctly Modify State

1. State cannot be modified directly.

By directly modifying the state, the component will not resend the render. E.g:

// 错误
this.state.title = 'React';

The correct way to modify is to use setState():

// 正确
this.setState({title: 'React'});
2. The update of State is asynchronous.

Call setState, the state of the component will not change immediately, setStatejust put the state to be modified into a queue, React will optimize the real execution timing, and React may setStatemerge multiple state modifications into one for performance reasons Status modification. So you can't rely on the current state to calculate the next state. When the state modification is actually performed, the dependent this.state is not guaranteed to be the latest state, because React will merge multiple state modifications into one. At this time, this.state is still equal to the state before these modifications occurred. Another thing to note is that you can't rely on the current props to calculate the next state, because the update of props is also asynchronous.

For example, for an e-commerce application, in our shopping cart, when the purchase button is clicked once, the purchase quantity will be increased by 1. If we click the button twice in a row, it will be called twice in a row this.setState({quantity: this.state.quantity + 1}). In React In the case of merging multiple modifications to one, it is equivalent to executing the following code equivalently:

Object.assign(
  previousState,
  {quantity: this.state.quantity + 1},
  {quantity: this.state.quantity + 1}
)

As a result, the latter operation overwrites the former operation, and the final purchase quantity only increases by 1.

If you really have such a requirement, you can use another function that receives a function as a parameter setState. This function has two parameters. The first parameter is the previous state of the component (the state before the component state is successfully modified this time). The second parameter is the current latest props of the component. As follows:

// 正确
this.setState((preState, props) => ({
  counter: preState.quantity + 1; 
}))
3. The update of State is a process of Shallow Merge.

When calling setStateto modify the state of a component, only the changed state variables need to be passed in, not the complete state of the component, because the update of the component state is a process of Shallow Merge. For example, the state of a component is:

this.state = {
  title : 'React',
  content : 'React is an wonderful JS library!'
}

When only the state needs titleto be modified, just titlepass the modified one to setState:

this.setState({title: 'Reactjs'});

React will merge the new titlestate into the original component state while retaining the original state content. The merged state is:

{
  title : 'Reactjs',
  content : 'React is an wonderful JS library!'
}

State与Immutable

React officially recommends treating state as an immutable object. On the one hand, if this.state is modified directly, the component will not re-render; on the other hand, all states contained in state should be immutable objects. When a state in the state changes, we should recreate a new state instead of directly modifying the original state. So, how do you create a new state when the state changes? According to the type of state, it can be divided into three cases:

1. The type of the state is an immutable type (number, string, boolean, null, undefined)

This is the simplest case, because the state is an immutable type, and you can directly assign a new value to the state to be modified. To modify the three states of count (number type), title (string type), and success (boolean type):

this.setState({
  count: 1,
  title: 'Redux',
  success: true
})
2. The type of the state is an array

If you have an array of state books, when adding a book to the books, use the array's concat method or ES6's array spread syntax:

// 方法一:使用preState、concat创建新数组
this.setState(preState => ({
  books: preState.books.concat(['React Guide']);
}))

// 方法二:ES6 spread syntax
this.setState(preState => ({
  books: [...preState.books, 'React Guide'];
}))

When taking part of the elements from books as the new state, use the slice method of the array:

// 使用preState、slice创建新数组
this.setState(preState => ({
  books: preState.books.slice(1,3);
}))

When filtering some elements from books, as a new state, use the filter method of the array:

// 使用preState、filter创建新数组
this.setState(preState => ({
  books: preState.books.filter(item => {
    return item != 'React'; 
  });
}))

Be careful not to use push, pop, shift, unshift, splice and other methods to modify the state of the array type, because these methods are modified on the basis of the original array, and concat, slice, and filter will return a new array.

3. The type of state is Plain Object

If there is a state owner in state, the structure is as follows:

this.state = {
  owner = {
    name: '老干部',
    age: 30
  }  
}

When modifying state, there are two ways:

1) Use ES6's Object.assgin method

this.setState(preState => ({
  owner: Object.assign({}, preState.owner, {name: 'Jason'});
}))

2 ) Use object spread properties

this.setState(preState => ({
  owner: {...preState.owner, name: 'Jason'};
}))

To summarize, the key to creating a new state is to avoid methods that directly modify the original object, and instead use methods that return a new object. Of course, you can also use some Immutable JS libraries, such as Immutable.js , to achieve a similar effect.

So, why does React recommend that the state of components be immutable objects? On the one hand, it is because immutable objects are convenient for management and debugging. For more information, please refer to here . On the other hand, for performance reasons, when the component states are all immutable objects, we shouldComponentUpdateonly need to compare the state in the component method. The reference can determine whether the state has really changed, thereby avoiding unnecessary rendermethod calls. When we use what React provides PureComponent, it is even more important to ensure that the component state is an immutable object, otherwise in the component shouldComponentUpdatemethod, the state comparison may be wrong.

Next notice:

React In-Depth Series 4: Component Lifecycle


New book recommendation "The Road to Advanced React"

Author: Xu Chao

Graduated from Zhejiang University with a master's degree, senior front-end engineer, long-term working in the energy Internet of things company Envision Intelligence. 8 years of software development experience, familiar with big front-end technology, rich experience in web front-end and mobile terminal development, especially in-depth understanding and practical experience of React technology stack and mobile Hybrid development technology.



The front-end team of the Meituan-Dianping advertising platform is recruiting front-end interns for 2019/2020 (in the direction of dynamic effects)

Interested parties email: [email protected]

Guess you like

Origin http://43.154.161.224:23101/article/api/json?id=324973762&siteId=291194637