Search code examples
reactjseasy-peasy

react easy-peasy component is not rerendered when the global state is modified


I'm new to react and this could be a fairly simple question to answer. I'm using easy-peasy for state management and I have an action that updates global state, but the component is not re-rendered even after global state is updated. Here is the codesandbox link. In this example, when the save button is clicked, I'm changing the record to "lock" status which should make it editable. https://codesandbox.io/s/reactjs-playground-forked-sbbh6?file=/src/App.js


Solution

  • As you are passing the store state to item again after clicking save, you need to listen for props change in Item and set the state again to trigger rerender.

    Therefore, the 1st step is to find out which value we want to monitor for changes. From the code, it is obvious that status is the best candidate.

    Item.js

    // not the final solution
    // monitor props status change, set the state again and trigger rerender
    useEffect(() => {
        setState({ ...state, ...props });
    }, [props.status]);
    

    However, there is a problem to tackle if we use props.status to trigger rerender.

    e.g.

    When you first click the save on item 2, item status change from open -> lock, the Item rerender. No problem!.

    But when you change the dropdown box from lock to open of item 2 and click the save again, Item will not rerender.

    As the updated store status of item 2 is still marked as lock, previous status is also lock, there is no changes at all in react point of view.

    You can check this codesandbox to simulate the issue.


    To address this issue, we need to introduce extra property to monitor its change for rerender. I used updatedAt to generate time on each update to let's react know there is a differences on the value and trigger rerender for us.

    modal.js

    items: [
        { id: 1212, title: "Watch mojos", subtitle: "", status: "open", updatedAt: null },
        { id: 1213, title: "Drink cheetos", subtitle: "", status: "open", updatedAt: null },
        { id: 1214, title: "Eat frodos", subtitle: "", status: "lock", updatedAt: null }
    ]
    
    saveItem: action((state, payload) => {
        console.log(payload);
        state.items = state.items.map((d) => {
          if (d.id === payload.id) {
            d.status = "lock";
            d.updatedAt = new Date(); // assign new date on each update
          }
          return d;
        });
    })
    

    Item.js

    useEffect(() => {
        setState({ ...state, ...props });
    }, [props.updatedAt]); // monitor update date change instead of status change
    

    Here is the workable codesandbox