0

I have a carousel component that receives the carousel items as a prop. I'm storing the currently active carousel item in the state of the carousel component. The carousel itself is a slider and controlled with a GSAP draggable. The number of carousel items might change, and then I want to reset the state so that the first item is active. How can I achieve this with the current React version? I tried:

static getDerivedStateFromProps(props, state) {
  if (state.openItem > props.items.length) {
    return {
      openItem: 0,
    };
  }
  return null;
}

But this will only reset if the current item is larger than the total number of items. I would like a way where I could compare the prevProps so that I can check if the total number of items have changed. If I set the state in componentDidUpdate, that might cause an endless render loop. I don't want to pull out the state to the parent component, because that would make the parent require too much functionality for the carousel component to be reusable.

Moriz Büsing
  • 368
  • 3
  • 17

2 Answers2

2

Store items in state and then use getDerivedStateFromProps like this :

static getDerivedStateFromProps(nextProps, prevState) {
  if (nextProps.items.length !== prevState.items.length) {
    return {
      openItem: 0,
      items: nextProps.items
    };
  }
  return null;
}

This is fine for the requirement but ideally you should figure out a way to check for content equality of the items and then fire the state change. You can use isEqual from lodash like this and replace equality check with :

if (_.isEqual(nextProps.items.length, prevState.items.length))

*note that isEqual performs deep equality checks and may have performance implications.

sudheer singh
  • 862
  • 1
  • 9
  • 23
  • Thanks, I actually came up with a similar solution in the meantime. I'm passing a hash of the objects into the component from the outside, which I set inside the state. Then in getDerivedStateFromProps I compare the new hash to the old one in the state. If they don't match, I reset the openItem. – Moriz Büsing Jan 30 '19 at 13:53
  • But doesn't sending hash from outside adds extra responsibility to the consumer of the carousel? – sudheer singh Jan 30 '19 at 13:58
  • yeah, youre right, better to compute this inside the component. – Moriz Büsing Jan 30 '19 at 14:11
  • i did it like this because i was passing actual components as props, so i wasn't certain if hashing those would still give the same hashes when the data was the same. – Moriz Büsing Jan 30 '19 at 14:12
0

You can use the getSnapshotBeforeUpdate() method for the compare the prevProps so that you can check if the total number of items have changed.

getSnapshotBeforeUpdate(prevProps, prevState) {
    // you can compare the previous prop value and previous state value as per you requirement
    if (prevProps.openItem.length > prevState.openItem.length) {
      // your code
    }
    return null;
  }
  • But then I would still have to go into componentDidUpdate and set the state there, right? At least that's what I see in the docs: https://reactjs.org/docs/react-component.html#getsnapshotbeforeupdate – Moriz Büsing Jan 30 '19 at 13:31