Updating useReducer 'state' using useEffect
Asked Answered
H

1

9

In my application, I am using React Hooks/Context API. Now I need to assign fetched data from localStorage to initialState.carts / state.carts whenever my Provider component did mount. It would possible if useEffect supports returning objects. But it's not possible to return object in useEffect!

Now how can I solve the problem?

Code is below,

const initialState = {
  books: books,
  carts: []
};

export const Context = createContext(initialState);

export const Provider = ({ children }) => {
  const [state, dispatch] = useReducer(reducer, initialState);

  useEffect(() => {
    if (localStorage.getItem("carts") !== null) {
      const fetchedCarts = JSON.parse(localStorage.getItem("carts"));
      //Here I want to assign 'fetchedCarts' array items in 'state.carts' or 'initialState.carts'
    }
  });
Hinshaw answered 23/2, 2020 at 16:31 Comment(1)
dispatch an action that will set state.carts to fetchedCartsSurovy
K
5

You have to dispatch an action to update your state variable.

if (localStorage.getItem("carts") !== null) {
      const fetchedCarts = JSON.parse(localStorage.getItem("carts"));
      dispatch({ type: 'UPDATE', payload: fetchedCarts })
}

So you have to add this action type to your reducer switch which you already used here:

const [state, dispatch] = useReducer(reducer, initialState);

En example of reducer structure:

const reducer = (state, action) => {
  switch (action.type) {
    case 'UPDATE':
      return { ...state, ...action.payload }
      break
    default:
      return state
  }
}

I believe that useEffect() should have a dependencies array (because the update of state will retrigger it in the current form).

It would possible if useEffect supports returning objects. But it's not possible to return object in useEffect!

The response from the useEffect should be a function (that function is being called before component is unmounted) - returning a object here would be a mistake.

Khamsin answered 23/2, 2020 at 16:38 Comment(3)
You might also want to add an example of useEffect with an empty dependencies array and assign action.payload to cart instead of spreading itSurovy
@Khamsin I did. But In useEffect it shown the "QuotaExceededError: Failed to execute 'setItem' on 'Storage': Setting the value of 'carts' exceeded the quota." error. And If I do it without useEffect, like you; It shows 'Too many re-renders. React limits the number of renders to prevent an infinite loop':(Hinshaw
@EbrahimKhalilAmid 1. you did something wrong in localStorage.setItem. 2. As Asaf mentioned above you can do it with `useEffect( () => { ... logic ... }, [] ) - an empty array will trigger that hook only once, you can't put that function directly into component code because it would be called on every rerender, and this function is causing rerendering.Khamsin

© 2022 - 2024 — McMap. All rights reserved.