Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Updating useReducer 'state' using useEffect

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'
    }
  });
like image 601
Ebrahim Khalil Amid Avatar asked Feb 23 '20 16:02

Ebrahim Khalil Amid


People also ask

Does useReducer update state?

The useReducer Hook is used to store and update states, just like the useState Hook. It accepts a reducer function as its first parameter and the initial state as the second.

How do I change initial state in useReducer?

You can just call the searchUsers() function in useEffect() to get some users and set the state. if you want to get initial users with some other logic you should probably write a different function and then call it when setting up the component.

Should I use useEffect or useLayoutEffect?

The main difference between the useEffect hook and the useLayoutEffect hook is that the useEffect hook serves asynchronously, whereas the useLayoutEffect hook works synchronously. In simple words, we can say that the difference between useEffect and useLayoutEffect is in the time at which these functions are invoked.

Does useEffect Rerender on state change?

Changing state will always cause a re-render. By default, useEffect always runs after render has run. This means if you don't include a dependency array when using useEffect to fetch data, and use useState to display it, you will always trigger another render after useEffect runs.


1 Answers

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.

like image 87
Deykun Avatar answered Oct 13 '22 10:10

Deykun