0

I'm building a kind of e-commerce app. As we know, every e-commerce app has wish list feature. In my product list, there's a like button on the card item. When user click it, it calls an API to set isLiked property to true (boolean) and updated the database.

When user click that card item, it should navigate him to it's detail page, which also has like button. I call the detail API in componentDidMount... Here's the thing:

I should render the like button with red color if the property of isLiked from detail API is true. So, to do that, I set my state in constructor with the props value:

constructor(props) {
    super(props);
    this.state = {
      isLikedForCompare: this.props.detailProduct.is_liked, // true
      isLiked: this.props.detailProduct.is_liked, // true
      selectedItem: ''
    };
  }

I add isLikedForCompare for comparing because we can't access this in getDerivedStateFromProps.

  static getDerivedStateFromProps(nextProps, prevState) {
    let defaultItem = ''
    // some code to get default item

    const { is_liked: isLiked } = nextProps.detailProduct;
    let selected = {};

    if (prevState.selectedItem === '') {
      selected = {
        selectedItem: defaultItem,
      };
    }

    return {
      ...selected,
      isLiked: prevState.isLikedForCompare !== isLiked ? isLiked : prevState.isLikedForCompare
    };
  }

I have that block of code about selectedItem which always satisfy the condition because the initial value is always empty. This code is works for other feature , so I need to let them alone, that's why my code is like this. So, move on... Now I can get the value of isLiked from props. The like button in my view is red now. But the problem is when I click that button. My expectation is when I click that button, the button change to white because I just change my state using this.setState but why getDerivedStateFromProps is called after setState?

This is a problem because: isLiked: prevState.isLikedForCompare !== isLiked ? isLiked : prevState.isLikedForCompare will always false. So my state isLike will always true!

How to fix this?

  • I'm pretty sure you could do all this derived "state" logic right in the render function. Saving props to state is a react anti-pattern, and there aren't many use-cases for needing `getDerivedStateFromProps`. If you think you need it, you still likely don't and can achieve the same behavior using the regular lifecycle functions. Check out the [react-lifecycle](https://projects.wojtekmaj.pl/react-lifecycle-methods-diagram/) diagram, be sure the check the "Show less common lifecycle" checkbox at the top. – Drew Reese Jun 24 '20 at 04:15
  • I guess you can use shouldComponentUpdate() to check if you really want to update/render the component when user toggles that like button and then inside componentDidMount() you can perform state operation. It's safe. Or the other advice it use PureComponent that will skip shouldComponentUpdate() check. Let me know if you need more help. – Mohit Jun 24 '20 at 04:24
  • @DrewReese do you mean setState `isLiked` with incoming props in render function above the return? – Ryandhika Rukmana Jun 24 '20 at 04:33
  • @Mohit I'm using PureComponent... So dou you think I should use `shouldComponentUpdate` ? well actually I am new in react-native so I will take the advice from @Drew Reese to check the diagram first. – Ryandhika Rukmana Jun 24 '20 at 04:37
  • No, I'm saying it seems your source of truth is being passed in via props, so don't waste time/effort duplicating and storing in local component state and all the work to keep them synchronized, just consume the `isLiked` value from the passed props object. – Drew Reese Jun 24 '20 at 04:42
  • No I meant to say that if you use PureComponent, then you can skip shouldComponentUpdate check. And as @DrewReese mentioned, if your props are in sync then you can use them as your source of truth and pass them directly to render the html. Now once your props are updated, your component will re-render itself with the updated props. – Mohit Jun 24 '20 at 04:51
  • Thanks for the answer @DrewReese and @Mohit. I will remember that. But I just solved it using redux haha that's an awesome tools. So the like button always receive props from reducer and every time I click that button, I updated `isLiked` property in reducer's state. Thanks anyway guys – Ryandhika Rukmana Jun 24 '20 at 10:19

0 Answers0