You may not need to use the derived state

React 16.4 fixes a BUG for getderiveDStateFromProps, which reproduces some known bugs in React Components. We are very sorry if this version leads to problems that have emerged. In this article, we will show some common back mode, and corresponding, we recommend the model.

For a long time, the lifecycle function ComponentWillReceiveProps is the only way to perform updates after the PROPS change. In the 16.3 version, we introduced an alternative version of lifecycle: getderiveDStateFromProps, try to achieve the same purpose in a more secure way. At the same time, we realize that there are many misunderstandings on how to use these two methods, and we find that anti-mode will lead to fine and chaotic errors. This bug that is repaired by version 16.4, so that the derived State is more controllable, making the BUG caused by the abuse easier to discover.

In all the backup modes below, ComponentWillReceiveProps and GetderiveDStateFromProps are common.

When do you use a derived state?

There is only one purpose for GetderiveDStateFromProps: Let components update State when PROPS changes. The last Blog shows some examples, such as the version of the proPs changes, modify the current scroll direction and load external data according to the PROPS change.

We did not provide a lot of examples because there was a rule of derived State. Most of the issues caused by derived State, not more than two reasons: 1, directly copy PROPS to State; 2, if PROPS and State are inconsistent, update State. The following example contains both cases.

If you are just for the cache, you don't have to use the derived state based on the result of the current PROPS calculation. Try MEMOIZATION? .
If you only use it to save PrOPS or update State after comparing after the current State comparison, then your component should be too frequently updated. Please continue reading.

Frequently bug in State

Nouns "controlled" and "non-controlled" are often used to refer to INPUTS, but can also be used to describe components that are frequently updated. If you use PROPS to enter data, components can be considered controlled (because components are incorporated by parent). The data is only stored in the components, and the non-controlled components (because there is no way to directly control State).
A common mistake is to mix the two. When a derived state value is also updated by the setState method, this value is not a single source value. The behavior described in the loading of external data is similar, but it is important to distinguish. In an example of loading external data, data Source and Loading have very clear and unique data sources. When the PROP changes, the status of Loading will change. Instead, State will only change when the PROP changes, unless other behavior changes this state.
The above conditions can cause problems if there is an unsatisfactory, and the most common is to modify data in two forms.

Back mode: copy PROP to State directly

The most common misunderstanding is that getderivedStateFromProps and ComponentWillReceiveProps will only call when PROPS "change". In fact, as long as the parent is renown, the two lifecycle functions will be reused, regardless of the "change" of PROPS. Therefore, direct replication in these two methods is unsafe. This will cause State without proper rendering.

Reproduce this problem. This emailInput component replicates Props to State:

class EmailInput extends Component{
    state = {email:this.props.email}
    render(){
        return <input onChange={this.handleChange} value={this.state.email}/>
    }
    handleChange = event => {
        this.setState({email:event.target.value})
    }
    componentWillReceiveProps(nextProps){
                 / / This overrides the State update in the component
        this.setState({email:nextProps.email})
    }
}

OK can I have. The initial value of State is passed by PROPS. When entering it, modify the state. But if the parent components render, all the things we entered will be lost! (View this example), even before resetting State, compare NextProps.Email! == this.State.email will still be updated.

In this small example, use ShouldComponentUpdate, comparing the props email whether it is modified and decide not to render. However, in practice, a component receives multiple PROPs, and the change in any PROP will cause re-rendering and incorrect state reset. Plus the in-line functions and objects PROP, create a completely reliable staycomponentupdate will become increasingly difficult. This example shows this situation. And the best practices for ShouldComponentupdate are used for performance improvement, rather than correcting unsuitable derived state.
I hope that the above can explain why the PROP to State is a very bad idea. Let us look at a related problem before looking for a solution: If we use the Email property update component in PROPS?

Back mode: Modify State after the PROPS changes

Continue to the above example, we can use PrOPS.Email to update the component, which prevents the rebound caused by state:

class EmailInput extends Component{
    state = {
        email:this.props.email
    }
    componentWillReceiveProps(nextProps){
        // As long as PROPS. Email changes to change State
        if(nextProps.email !== this.props.email){
            this.setState({
                email:nextProps.email
            })
        }
    }
}

In the example, ComponentWillReceiveProps is used, using getderivedStateFromProps is also the same.

We have made a big improvement. Now the components will only change when the PROP changes.

But there is still a problem. Imagine, if this is a password input component, this input box does not reset when you have two accounts that equally email, and this input box will not reset (used to log in to the user). Because the PROP value from the parent component has not changed! This will make users surprises, because this looks like a password that helps a user sharing another user, (see this example).

Although this design has problems, such mistakes are common, (I have made such a mistake). Fortunately, there are two options to solve these problems. The key to both is that any data must ensure that there is only one source of data and avoid directly copying it. Let's take a look at these two programs.

Suggested mode

Suggestion: Fully controllable components
One way to prevent the above problems is to remove State from the component. If you contain email in the prop, we don't have to worry about it and the State conflict. We can even convert the emailinput into a lightweight function component:

function EmailInput(props){
    return <input onChange={props.onChange} value={props.email}/>
}

This will use the simplest way to complete the components we need. But if we still want to save a temporary value, you need to manually perform save this action manually. (Click to view this mode's demo).

Suggestion: Non-controllable components with key

Another option is to let components store temporary email state. In this case, the component can still receive "initial value" from the Prop, but the value after the change is not related to the proposition:

class EmailInput extends Component{
     state = {
         email:this.props.defaultEmail
     }
     handleChange = event =>{
         this.setState({
             email:event.target.value
         })
     }
     render(){
         return <input onChange={this.handleChange} value={this.state.email}/>
     }
 }

In the example of this password manager, in order to switch different values ​​in different pages, we can use the special react attribute of KEY. When Key changes, React creates a new instead of updating a existing component. Keys is generally used to render dynamic lists, but it can also be used here. In this example, when the user is entered, we use the user ID as a key to recreate a new Email Input component:

<EmailInput defaultEmail = {this.PaymentResponse.user.email} key={this.props.user.id}/>

Each ID change will recreate EmailInput and reset its status to the latest defaultemail value. (Click to view this mode) Use this method, do not have to add Key to each time, add Key to the entire form, more reasonably. Every time the key changes, all components in the form will be recreated with new initial values.

In most cases, this is the best way to deal with resetting State.

In most cases, this is the best way to deal with resetting State.

Notice

This sounds very slow, but this performance can be ignored. If there is a significant logic on the update of the component tree, it will be faster because the sub-component DIFF is omitted.

Option 1: Reset non-controlled components with PROP ID
If in some cases, Key does not work (probably the overhead of the component initialization is too large), a cumbersome but feasible solution is to observe the changes in UserID at GetderiveDStateFromProps:

class EmailInput extends Component{
     state={
         email:this.props.defaultEmail,
         prevPropsUserId:this.props.userID
     }
     static getDerivedStateFromProps(props,state){
                   // As long as the current User changes
                   // Reset all the status related to User
                 // This example is only email and user related
        if(props.userID !== state.prevPropsUserId){
            return{
                prevPropsUserID:props.userID,
                email:props.defaultEmail
            }
        }
        return null
     }
 }

If you are willing, you can only reset a small portion of State (click to view the presentation of this mode).

Notice

The above example uses getderivedStateFromProps, which is the same as ComponentWillReceiveProps.

Option 2: Use an instance method to reset non-controlled components
There are fewer situations that even if there is no suitable key, we also want to recreate the component. One solution is to give a random value or incremented value as a key, and another is to force reset internal state with an instance method:


 class EmailInput extends Component{
     state = {
         email:this.props.defaultEmail
     }
     resetEmailForNewUser(newEmail){
         this.setState({
             email:new Email
         })
     }
 }

The parent component can then use the REF to call this method. (Click to view this mode's demo).

REFS is useful in some cases, such as this. But usually we recommend caution. Even a demonstration, this ordered method is also not ideal because it causes twice instead of rendering.

Summary

Review, when designing components, it is important to determine that components are controlled components or non-controlled components.

Do not copy (mirror) value to State, but to implement a controlled component, then merge two values ​​in the parent component. For example, do not passively accept PrOPS. Value in the subcomponents and track a temporary state.value, and manage State.DraftValue and State.commmittedValue in the parent component, directly control the value in the subcomponents. This data is more clearly predictable.

For uncontrolled components, you can choose the following ways when you want to reset State when the PrOP changes (usually id), you can choose the following ways:

Recommendation: Reset all of the initial state, using the key attribute
Option 1: Only change certain fields, observe changes in special properties (such as Props.Userid).
Option 2: Use the REF to call the instance method.

Intelligent Recommendation

Oracle often uses statements that you may need to use sometimes

Written in front: The following are some of the statements that may need to be used in the work. Some of the statements that have been sorted out by various sorts are useful. If the query is incorrect...

Use Scala Map's mapValues ​​with caution, you may need transform

Before stepping on the pit of mapValues, I believe most people would think that the logic of mapValues ​​is the same as all other map methods: apply a map function to all values ​​in the Map and retur...

Points you may need to pay attention to during the use of RestTemplate

When RestTemplate sets parameters in a get request, the parameters followed by the url must not be the param value after encode, because it will encode again A URL can be encoded multiple times, each ...

You may need to use return in JS, summarize and explain! ! !

return value The Return statement terminates the function execution and returns a specified value to the caller of the function (function name + () is equal to the return value of the function) If the...

【you may need to restart the kernel to use updated packages】

@PIP Insatll command is not installed in the third party library you may need to restart the kernel to use updated packages When the PIP Install command cannot be installed in the Jupyter, the third -...

More Recommendation

You no longer need to use state management such as Redux, Mobx, Flux, etc.

Unstated Next README Chinese translation Foreword The author of this library hopes to implement state management directly using the React built-in API. After reading the instructions of this library, ...

Annotation - you may need to know these

In the daily development work, especially when using some popular open source frameworks, we inevitably use annotations, the scope of annotations is more and more extensive, and after using annotation...

HashMap - you may need to know these

HashMap is a mapping data type that Android programmers (and of course Java programmers) often use. With the JDK version update, JDK1.8 has some optimizations compared to the underlying implementation...

Agent - you may need to know these

The agent is a very common knowledge point in our daily development, and it is also often asked in our interviews. This blog post takes everyone to learn and analyze the relevant content of the agent....

[Translation] You may not need Redux

Original linkYou Might Not Need Redux People often choose Redux before they need it. What if our application can't expand without it? Later, developers were confused about the direction in which REdux...

Copyright  DMCA © 2018-2026 - All Rights Reserved - www.programmersought.com  User Notice

Top