Search code examples
javascriptreactjsreact-propsreact-state

Normal/Standard way to compare prevProps in componentDidUpdate


This has come about because during prototyping, I'm finding that incoming new prop(s) might be an array of complex objects, so prevProps.myProp===this.props.myProp is always false. JSON.stringifying them both before comparison works, but feels unreliable.

I'm trying to write a reusable function for Class Components that compares prev/new props in react's componentDidUpdate. For example:

componentDidUpdate(prevProps) {
    // First, get difference here, possibly using a lib like npm 'deep-object-diff'.
    // ...or just JSON.stringify both and do string comparison
    const changes = getTheDifference(prevProps, this.props)

    // Don't do anything if there's no changes.
    if (!changes) return

    // Then I want to do something like:
    this.setState( Object.assign(this.state, changes) )
}

...that would mean any time the incoming props change, those get immediately reflected in state. I'm having some issues finding a suitable diff lib, but I still feel like I shouldn't be having to do this and am missing something - is there a generally accepted "normal" way to do this, or is me having this problem just a sign of:

  • The component is trying to do too much/state too complex?
  • I should be mapping props to state with something like Redux? (trying to avoid this until absolutely necessary)
  • I'm overthinking it, sometimes the logic in a component's componentDidUpdate is just complex and unique?

Solution

  • that would mean any time the incoming props change, those get immediately reflected in state

    Yes, that's wrong. When I first started out I was doing the same thing.

    1. state is something "owned" by that component (noteworthy: not all components need state at all!).
    2. props are something that are "owned" by a higher component.

    Best example:

    ComponentA passed an id to ComponentB as a prop. ComponentB uses that id to make an API request (for example).

    The status/results of that API request form part of ComponentB's state (it's "owned" by your component). The id passed in as a prop is NOT part of ComponentB's state (it's owned by ComponentA, or maybe somewhere higher in the tree that passed it as a prop to ComponentA).

    When the id prop changes, ComponentB will need to make another API request.

    EDIT:

    The complexity of lifecycle methods is why React has highly encouraged functional components.

    You should think of components as functions. It's a lot easier to write the logic if you just think of it as input -> output.

    componentDidUpdate has been moved to useEffect with a dependency list so you can say - run this function, but only when this prop changes - which is a nice way to break down massive componentDidUpdate methods into tiny readbale/testable chunks.

    I've heard a lot of people say hooks ruined react, but I highly disagree with them. React saw the problems people were running into in the community by misusing class/instance based components and instead of lecturing about how to use them correctly, they nudged people to writing better components by introucing a simpler API - functions, while they still can and will be abused - are generally simpler to deal with than classes and align nicely with composition over inheritance and declarative over imperative.