Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Why do I need prevProps with prevState in componentDidUpdate()?

Tags:

reactjs

I have built a simple counter app:

class Counter extends React.Component {

  constructor(props) {
    super(props);
    this.handleAddOne = this.handleAddOne.bind(this);
    this.handleMinusOne = this.handleMinusOne.bind(this);
    this.handleReset = this.handleReset.bind(this);
    this.state = {
      count: 0
    };
  }

  componentDidMount() {
      const stringCount = localStorage.getItem('count');
      const count = parseInt(stringCount);

      if (isNaN(count) === false) {
        this.setState(() => ({ count }));
      } 
  }

  componentDidUpdate(prevProps, prevState) {
    if (prevState.count !== this.state.count) {
      localStorage.setItem('count', this.state.count);
      console.log('componentDidUpdate');
    }
  }

  handleAddOne() {
    this.setState((prevState) => {
      return {
        count: prevState.count + 1
      }
    });
  }
  
  handleMinusOne() {
    console.log('handleMinusOne');
    this.setState((prevState) => {
      return {
        count: prevState.count - 1
      }
    });
  }
  
  handleReset() {
    this.setState(() => {
      return {
        count: 0
      }
    });
  }

  render() {
    return (
      <div>
        <h1>Count: {this.state.count}</h1>
        <button onClick={this.handleAddOne}>+</button>
        <button onClick={this.handleMinusOne}>-1</button>
        <button onClick={this.handleReset}>reset</button>
      </div>
    );
  }
}

ReactDOM.render(<Counter />, document.getElementById('app'));

The question I have is with componentDidUpdate(). In it, I am checking to see if the prevState.count is not the same as the this.state.count. If it is not the same, then I set localStorage to the new count. If it is same, I do nothing.

In the current componentDidUpdate(), I need prevProps as an argument for this function to work correctly. For example, if I just have this:

componentDidUpdate(prevState) {
    if (prevState.count !== this.state.count) {
      localStorage.setItem('count', this.state.count);
      console.log('componentDidUpdate');
    }
  }

Then the component sets localStorage every time the reset button is pressed repeatedly, even though the count remains at 0.

What is going on? Why do I need prevProps for componentDidUpdate() to work correctly, if I am never using props in that function?

like image 443
InspectorDanno Avatar asked Dec 11 '18 23:12

InspectorDanno


People also ask

What is prevState in componentDidUpdate?

Syntax: componentDidUpdate(prevProps, prevState, snapshot) Parameters: Following are the parameter used in this function: prevProps: Previous props passed to the component. prevState: Previous state of the component. snapshot: Value returned by getSnapshotBeforeUpdate() method.

What is prevState in setState?

prevState() is the same as the setState but the only difference between them is that if we want to change the state of a component based on the previous state of that component, we use this. setState() , which provides us the prevState . Let's check an example of a counter app.

What do you usually do in componentDidMount () and componentDidUpdate ()?

componentDidMount() will be rendered immediately after a component is mounted. This method will render only once and all the initialization that requires DOM nodes should go here. Setting state in this method will trigger a re-rendering. componentDidUpdate() is invoked immediately every time the updating occurs.

What triggers componentDidUpdate?

The componentDidUpdate() hook is used to trigger an action once we find an update in the component, but make sure this hook method does not get called at the time of the initial render of the component.


1 Answers

The first parameter in componentDidUpdate is prevProps. The second parameter is prevState. The documentation clearly states that:

componentDidUpdate(prevProps, prevState, snapshot)

This

componentDidUpdate(prevState) {...}

is not a correct signature for the hook. Even though the first parameter was called prevState, it contains previous props.

It's possible to alternate function parameters based on its arity but this isn't implemented in React and considered a bad practice in general because this leads to more complex signatures.

To not cause linter warnings, unused parameters can be underscored by convention:

componentDidUpdate(_prevProps, prevState) {...}
like image 162
Estus Flask Avatar answered Nov 03 '22 01:11

Estus Flask