Mad Max
Mad Max

Reputation: 283

Take an action on props change in ReactJS

I need to use current props and previous props value in my React component. So i did it like this

state = {
    current: null,
    previous: null,
};

componentWillReceiveProps(nextProps) {
    if (nextProps.amount !== this.state.current) {
        this.setState({previous: this.state.current, current: nextProps.amount});
    }
}

...

render() {
    const {previous, current} = this.state;

    return (
        ...
        <CountUp className="counter" start={previous} end={current} duration={1}/>
        ...
    )
}

It works fine, but is it good React practise to do it like this? Are there others "good" ways to do it?

Upvotes: 5

Views: 13892

Answers (3)

afryingpan
afryingpan

Reputation: 363

I'd like to update this answer for anyone else who comes here from Google. As of v16.8.6, componentWillReceiveProps has been marked as legacy, and is not recommended to use. Instead you should use componentDidUpdate and update your state based on the new props and previous props/previous state.

componentDidUpdate(prevProps, prevState) {
   if (this.props.someVal !== prevState.someVal) {
     this.setState({ previous: prevState.someVal, current: this.props.someVal });
   }
}

Obviously, whether you check the previous state or the previous props is up to your discretion/situation. You can implement componentDidUpdate with or without the parameters, but if you want prevState you must declare prevProps.

React Update Lifecycle

componentDidUpdate()

Upvotes: 6

Shubham Khatri
Shubham Khatri

Reputation: 282050

As of v16.2.0, componentWillReceiveProps is the right place to update state, based on prop changes and since you want to use both current state and previous state in render, you need to maintain, two different state variables as you are doing

However, when you update the state based on previous state, use functional setState method

Check this answer for more details

When to use functional setState

componentWillReceiveProps(nextProps) {
    if (nextProps.amount !== this.state.current) {
        this.setState(prevState => ({ previous: prevState.current, current: nextProps.amount }));
    }
}

According to the latest RFC to React

State derived from props/state

The purpose of this pattern is to calculate some values derived from props for use during render.

Typically componentWillReceiveProps is used for this, although if the calculation is fast enough it could just be done in render.:

From v16.3.0 onwards, you would make use of

static getDerivedStateFromProps(nextProps, prevState) {
    if (
      !prevState ||
      prevState.current !== nextProps.amount
    ) {
      return {
        previous: prevState.current,
        current: nextProps.amount
      };
    }
}

Upvotes: 7

KolaCaine
KolaCaine

Reputation: 2187

You can use an arrow function in your setState object. Like this :

this.setState((prevState) => {
      return { yourState: prevState.yourState }
    })

prevState is a default name but you can replace the name as you want

Upvotes: 2

Related Questions