Tugrul
Tugrul

Reputation: 1808

How to handle props changes without using componentWillReceiveProps in React

I've been working on a project which is coded with React. I have a component set that I implemented many components for my own requirements. Many of these act like a composite component. For example, TextBox component which has its own label, own error message mechanism and own input filter etc. Moreover, you know, components have props to manage sth.

Everytime to update my component view (render), I use componentWillReceiveProps and I compare the props changes.

But everytime implementing the componentWillReceiveProps method is so repulsive.

Is there any way to pass props from top to down without using componentWillReceiveProps. I don't want to compare props changes manually. Is there any way to do it automatically.

When I change the props in parent, I'd like to update all views just changing the some prop values from top to down.

I'm not an react expert and performance is not my first purpose also!

One more thing that the answer is not use Redux!

I'm waiting your creative approaches and helpful ideas.

Upvotes: 3

Views: 24393

Answers (3)

Benjamin Robinson
Benjamin Robinson

Reputation: 368

Without seeing the code for the particular thing you're working on, I may be missing something about what you're doing...

As others have commented, React will re-render your component if new props are provided, regardless of whether or not you implement componentWillReceiveProps -- the only reason to implement it is to do some kind of specific comparison or set a state based on new prop values.

From the React docs (emphasis mine):

componentWillReceiveProps() is invoked before a mounted component receives new props. If you need to update the state in response to prop changes (for example, to reset it), you may compare this.props and nextProps and perform state transitions using this.setState() in this method.

Note that React may call this method even if the props have not changed, so make sure to compare the current and next values if you only want to handle changes. This may occur when the parent component causes your component to re-render.

In other words, if you have a component like:

<TextBox title={"Foo"} content={"Bar"} />

That internally passes prop changes on to a couple of child components like:

class TextBox extends React.Component {
  
  render() {
    return (
      <div className={'text-box'}>
        <Title text={this.props.title} />
        <Body text={this.props.content} />
      </div>
    );
  }
  
}

Then each time new props are passed to <TextBox>, <Title> and <Body> will also get re-rendered with their new text props, and there's no reason to use componentWillReceiveProps if you're just looking to update with prop changes. React will automatically see the changes and re-render. And React handles diffing and should fairly efficiently re-render only things that have changed.

However, if you have a separate state value that needs to be set in response to props, for example, if you wanted to show a "changed" state (or whatever) on the component if the new props are different, then you could implement componentWillReceiveProps, like:

class TextBox extends React.Component {
  
  componentWillReceiveProps(nextProps) {
    if (this.props.content !== nextProps.content) {
      this.setState({changed: true});
    }
  }

  render() {
    
    const changed = this.state.changed ? 'changed' : 'unchanged';

    return (
      <div className={`text-box ${changed}`}>
        <Title text={this.props.title} />
        <Body text={this.props.content} />
      </div>
    );
  }
  
}

If you're trying to prevent re-render in cases where it's unnecessary for performance, do as Andrey suggests and use shouldComponentUpdate: https://facebook.github.io/react/docs/react-component.html#shouldcomponentupdate

TLDR; unless you're setting component state from props, there's likely no need to run new props through componentWillReceiveProps

UPDATE Feb 2018: in a future release, React will be deprecating componentWillReceiveProps in favor of the new getDerivedStateFromProps, more info here: https://medium.com/@baphemot/whats-new-in-react-16-3-d2c9b7b6193b

Upvotes: 11

Deng  Zhebin
Deng Zhebin

Reputation: 1262

Please consider pureComponent which by defualt implements the shouldComponentUpdate inside which shallow equals is used for comparison between previous and next

try following codes:

class MyComponent extends PureComponent {...}

Upvotes: 1

Andrii Muzalevskyi
Andrii Muzalevskyi

Reputation: 3329

There are few suggestions:

  • Don't copy props into state in componentWillReceiveProps - just render directly from this.props
  • If your component need performance tweak (and only if there is problem with performance):

The general approach, how to develop text-box-like components is to keep it stateless.Component renders props directly, and notifies parent component about changes, it don't cares about managing value.

Hope this will help

Upvotes: 2

Related Questions