Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

this.props and NextProps the same after parent state changes #7121

Closed
NateBrady23 opened this issue Jun 25, 2016 · 3 comments
Closed

this.props and NextProps the same after parent state changes #7121

NateBrady23 opened this issue Jun 25, 2016 · 3 comments

Comments

@NateBrady23
Copy link

I am changing the parent state of a component from a nested child after passing a callback method down through props. This is working as expected, as the state is being changed and my components are updating properly. However, while optimizing my rendering I noticed that for this particular prop settings it ends up being the newest prop in both componentWillReceiveProps and shouldComponentUpdate.

So on my parent component I have a setting object like so:

/*********************************************************************
* in my parent component
*/

class Parent extends React.Component {

constructor(props) {
  super(props);

  this.state = {
    settings: {
      one: true,
      two: true
    }
  };
}

toggleSetting = (key) => {
    const settings = this.state.settings;
    console.log('old settings: ', settings); // Produces expected (old state) results
    settings[key] = !settings[key];
    this.setState({ settings });
    console.log('new settings:', this.state.settings); // Produces expected (new state) results
};

render() {
  return (
    <Child settings={this.state.settings} toggleSetting={this.toggleSetting} />
  );
}

/**********************************************************************
* in my child component
*/

componentWillReceiveProps(nextProps) {
  console.log(this.props.settings, nextProps.settings); // Both new results
}

// this would stop rerendering because it's always true for some reason
shouldComponentUpdate(nextProps) {
  return (this.props.settings.one === nextProps.settings.one); 
}

// in my child render
<GrandChild 
    settings={this.props.settings}
    toggleSetting={this.props.toggleSetting} />

/**********************************************************************
* in my grandchild render
*/

<SomeTag
    settings={this.props.settings}
    onClick={()=>this.props.toggleSetting('one')} />

All behavior works as expected, except for the incoming props and "old" props being the same

@aweary
Copy link
Contributor

aweary commented Jun 25, 2016

It's likely because you're mutating the current state object in your toggleSetting method

 const settings = this.state.settings;
    console.log('old settings: ', settings); // Produces expected (old state) results
    settings[key] = !settings[key];

Since you're mutating the current state object and then using that to set the next state, you're getting the same reference in your current and next state. You should always treat state as immutable

toggleSetting = (key) => {
    const settings = this.state.settings;
    this.setState({ 
       settings: !this.state.settings
     });
};

React expects you to treat state as immutable, so doing it this way is always recommended. See
https://facebook.github.io/react/docs/component-api.html#setstate

Notes:
NEVER mutate this.state directly, as calling setState() afterwards may replace the mutation you made. Treat this.state as if it were immutable.
setState() does not immediately mutate this.state but creates a pending state transition. Accessing this.state after calling this method can potentially return the existing value.

@NateBrady23
Copy link
Author

@aweary of course. I would normally do the snippet you just showed but I am trying to change a particular key within an object on state. As it turns out, I am doing this incorrectly in a few places. Had my console.log been 1 line lower, I would have caught that I was changing the original state this way. I often forget that. Anyway I've found the Immutability Helpers which work great. Thanks for the response.

@PrincieRakotoarivony
Copy link

Thanks, you really helped me 😊😊

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

3 participants