简体   繁体   中英

Why would a timer on a Redux reducer help trigger a re-render

I came across some weird behavior that I would feel safer to understand

Below is the code of my reducer. I can not get why, but with this code the component tied to the redux state does not re-render . I can tell with the developper tools that the state is properly updated.

const initialState = {
  allItems: [],
  favItems: [],
}

export default (state = initialState, action) => {
  let allItems

    case CREATE_ITEM:
      allItems = state.allItems
      allItems.unshift(action.item)
      return {
        ...state,
        allItems: allItems,
      }
}

Comparing with other actions in my reducer, I finally guess that there was something about the time cost of the operation, some other operations a bit more complicated seemed to work better...

So I added a timer

case CREATE_ITEM:
      allItems = state.allItems
      allItems.unshift(action.item)
      setTimeout(() => {
        return {
          ...state,
          allItems: allItems,
        }
      }, 0)

And boom, it worked !

I really don't like this highly hacky solution.

Does anyone has any idea about what is happening and how I could solve this in a better way.

Notes :

  • I'm working on react-native, but it doesn't seem related
  • In the component, the redux state is selected with the useSelector hook
const items = useSelector((state) => state.items.allItems)

"allItems.unshift(action.item)" adds data directly to the reducer state, because allItems is referenced to redux state variable. So before returning the state you are updating the reducer. After returning the state there won't be any change in the redux data so component is not getting re-rendered.

For better understanding refer to this answer https://stackoverflow.com/a/48819216/7822241

Here is the solution, with the help of Mohan Krisgna Sai answer.

I was indeed mutating the state without knowing it, because when you assign a variable to a reference type (ie: an object), the variable only holds a reference to the memory location where the object is actually stored, not the actual object itself. Further details here : https://stackoverflow.com/a/50840423/13337619

So, this, is mutating the state

allItems = state.allItems
allItems.unshift(action.item)

The solution is straightforward :

    case CREATE_ITEM:
      return {
        ...state,
        allItems: [action.item, ...state.allItems],
      }

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM