BikoK
BikoK

Reputation: 55

react - force componentDidUpdate() when props are same value

In my component im trying to sync the received props with the current state in order to make it visible from outside (I know this is an anti-pattern, but I haven't figured out another solution to this yet. Im very open to suggestions!).

Anyways, this is what I've got:

export class PopupContainer extends React.Component {
  state = {
    show: false,
  };

  shouldComponentUpdate(nextProps, nextState) {
    if (this.props.show === nextProps.show) return true;
    return true;
  }

  componentDidUpdate(prevProps, prevState, snapshot) {
    // if popup shown, fade it out in 500ms
    if (this.props.show !== prevProps.show)
      this.setState({ show: this.props.show });

    if (this.state.show) {
      setTimeout(() => this.setState({ show: false }), 2000);
    }
  }

  render() {
    return <Popup {...{ ...this.props, show: this.state.show }} />;
  }
}

And in my external component I'm rendering the container :

<PopupContainer
          show={this.state.popup.show}
          message={this.state.popup.message}
          level={this.state.popup.level}
        />

Now when I initially set this.state.show to true it works, but every successive assignment which is also true without any false assignment inbetween doesn't work. How do I force componentdidUpdate() to fire anyways even if the props are the same value? shouldComponentUpdate() didn't seem to solve the problem.

Thank you!

Edit: I noticed that the render() method is only called in the parent element. It seems like as there is no change in properties for the child, react doesn't even bother rerendering the childern which somehow makes sense. But how can I force them to rerender anyways?

Upvotes: 5

Views: 2025

Answers (1)

brinch
brinch

Reputation: 2614

This is kind of a hack, but it works for me.

In the child class

Add a property to state in constructor - let's call it myChildTrigger, and set it to an empty string:

this.state = {
   ...
   myChildTrigger: ''
}

then add this to componentDidUpdate:

componentDidUpdate(prevProps) {
   if(this.state.myChildTrigger !== this.props.myParentTrigger) {

      // Do what you want here

      this.setState({myChildTrigger: this.props.myParentTrigger});
   }
}

In the parent class

Add a myParentTrigger to state in constructor:

this.state = {
   ...
   myParentTrigger: ''
}

In the render method, add it as a prop, like this:

<ChildClass ... myParentTrigger={this.state.myParentTrigger} />

Now you can trigger a call to componentDidUpdate to execute whatever is inside the if-statement, just by setting myParentTrigger to a new value, like:

this.setState({ myParentTrigger: this.state.myParentTrigger + 'a' });

Upvotes: 1

Related Questions