DEV Community

Cover image for prevState with useReducer hook in React.
Ivan Jeremic
Ivan Jeremic

Posted on • Edited on

prevState with useReducer hook in React.

I wanted to share not only how I currently do State Management with React Context but also what I do when I need prevState, If there are any suggestions for improvement let me know.

Hope this helps some of you :)

import React, {
  createContext,
  useReducer,
  useContext,
  useEffect,
  useRef,
} from 'react';

/* ******* */
/* Reducer */
/* ******* */
function reducer(state, action) {
  switch (action.type) {
    case 'LOGIN':
      return {
        ...state,
        isLoggedIn: true,
      };

    default:
      return state;
  }
}

const StateContext = createContext({});
const DispatchContext = createContext({});
const PrevStateContext = createContext({});

const StateContainer = (Context) => {
  const context = useContext(Context);
  if (context === undefined) {
    throw new Error('Context must be used within a Provider');
  }
  return context;
};

const DispatchContainer = (Context) => {
  const context = useContext(Context);
  if (context === undefined) {
    throw new Error('Context must be used within a Provider');
  }
  return context;
};

const PrevStateContainer = (Context) => {
  const context = useContext(Context);
  if (context === undefined) {
    throw new Error('Context must be used within a Provider');
  }
  return context;
};

const AppContextProvider = (props) => {
  const { children } = props;

  const [state, dispatch] = useReducer(reducer, {
    isLoggedIn: false,
  });

  function usePrevious(value: any) {
    const ref = useRef();
    useEffect(() => {
      ref.current = value;
    });
    return ref.current;
  }

  let prev = usePrevious(state);

  return (
    <StateContext.Provider value={state}>
      <DispatchContext.Provider value={dispatch}>
        <PrevStateContext.Provider value={prev === undefined ? {} : prev}>
          {children}
        </PrevStateContext.Provider>
      </DispatchContext.Provider>
    </StateContext.Provider>
  );
};

const useAppContext = () => {
  return [
    StateContainer(StateContext),
    DispatchContainer(DispatchContext),
    PrevStateContainer(PrevStateContext),
  ];
};

export { AppContextProvider, useAppContext };
Enter fullscreen mode Exit fullscreen mode

Top comments (4)

Collapse
 
lyrod profile image
Lyrod

I am puzzled by the usePrevious hook, a new instance is created for each render

Collapse
 
ivan_jrmc profile image
Ivan Jeremic • Edited

Thanks, Any recommendations?

Collapse
 
lyrod profile image
Lyrod

I think, creating the function outside of the component (for example: in a folder "hooks") is better.

Thread Thread
 
ivan_jrmc profile image
Ivan Jeremic

Yea I wanted somehow to include the code for the hook here so people can see it, but maybe I should have put it outside the Provider which would be the same effect as in a separate folder. Thanks