Follow

Keep Up to Date with the Most Important News

By pressing the Subscribe button, you confirm that you have read and are agreeing to our Privacy Policy and Terms of Use
Contact

React Context resets after changing routing using useNavigate

I am having an issue where my react context data resets whenever I change routes using React-Router-DOM v6 as my routing library. I’m very confused because while I understand manually entering a new URL would cause a reload, I am utilizing useNavigate to change routes, yet none of my data persists.

I have been at this for a while now but no luck solving the issue.

Here is a breakdown of my code.

MEDevel.com: Open-source for Healthcare and Education

Collecting and validating open-source software for healthcare, education, enterprise, development, medical imaging, medical records, and digital pathology.

Visit Medevel

First, I created an AuthProvider, AuthContext, and a useAuth hook to handle the global auth context.

const authReducer = (state: InitialState, action: Actions) => {
  switch (action.type) {
    case ActionType.SET_AUTH:
      return { ...state, ...action.payload };
    case ActionType.REMOVE_AUTH:
      return {};
    default:
      return state;
  }
};

export const useAuth = () => {
  const [state, dispatch] = useReducer(authReducer, {});

  const setAuth = useCallback(
    (data: InitialState) => {
      dispatch({ type: ActionType.SET_AUTH, payload: data });
    },
    [dispatch]
  );

  const removeAuth = useCallback(() => {
    dispatch({ type: ActionType.REMOVE_AUTH, payload: {} });
  }, [dispatch]);

  return { auth: state, setAuth, removeAuth };
};

const initialAuthContext: UseAuthContext = {
  auth: {},
  setAuth: () => {},
  removeAuth: () => {},
};

export const AuthContext = createContext<UseAuthContext>(initialAuthContext);

export const AuthProvider = ({ children }: AuthContextChildren) => {
  return (
    <AuthContext.Provider value={useAuth()}>{children}</AuthContext.Provider>
  );
};

Next, I added the AuthProvider to my App.tsx.

function App() {
  ...
  return (
    <Box>
      <ThemeProvider theme={theme}>
        <AuthProvider>
          <BrowserRouter>
            <Router />
          </BrowserRouter>
        </AuthProvider>
      </ThemeProvider>
    </Box>
  );
}

Inside my <Router /> I aded the respective routes for Dashboard and Project.

const Router = () => {
  ...
  return (
    <Box sx={{ display: "flex" }}>
      ...
      <Routes>
        ...
        <Route
          path={SectionRoutes.Dashboard} // /dashboard
          element={<Dashboard updateCurrentSection={updateCurrentSection} />}
        />
        <Route
          path={SectionRoutes.Project} // /project
          element={<Project updateCurrentSection={updateCurrentSection} />}
        />
      </Routes>
    </Box>
  );
};

Inside <Dashboard /> I added an accessToken to my auth context.

const Dashboard = () => {
  ...

  const { auth, setAuth } = useAuth();
  useEffect(() => setAuth({ accessToken: "" }), []); // UPDATING CONTEXT
  console.log(auth);

  return (
    ...
  );
};

Utilizing my apps SideNav I navigated to <Project /> using const navigate = useNavigate().

<ListItemButton
   onClick={() => navigate(item.path)} // using useNavigate from 'react-router-dom'
   selected={isSelected}
>

I expect to see my auth context have a key value pairing for accessToken: "" but I get {}.

const Project = ( => {
  ...

  const { auth, setAuth } = useAuth();
  console.log(auth); // CONTEXT IS EMPTY

  return (
    ...
  );
};

export default Project;

I tried a multitude of things such as changing how the context was written, seeing if I made an error with the routing, and searching Stack Overflow, but all the answer left me wanting.

>Solution :

Each useAuth hook is managing its own state and callbacks.

Move the logic into the AuthProvider component so the single Context value can be provided to all consumers, update the useAuth hook to return the context value.

const authReducer = (state: InitialState, action: Actions) => {
  switch (action.type) {
    case ActionType.SET_AUTH:
      return { ...state, ...action.payload };
    case ActionType.REMOVE_AUTH:
      return {};
    default:
      return state;
  }
};

const initialAuthContext: UseAuthContext = {
  auth: {},
  setAuth: () => {},
  removeAuth: () => {},
};

export const AuthContext = createContext<UseAuthContext>(initialAuthContext);

export const useAuth = () => useContext(AuthContext);

export const AuthProvider = ({ children }: AuthContextChildren) => {
  const [state, dispatch] = useReducer(authReducer, {});

  const setAuth = useCallback((data: InitialState) => {
    dispatch({ type: ActionType.SET_AUTH, payload: data });
  }, [dispatch]);

  const removeAuth = useCallback(() => {
    dispatch({ type: ActionType.REMOVE_AUTH, payload: {} });
  }, [dispatch]);

  return (
    <AuthContext.Provider value={{ auth: state, setAuth, removeAuth }}>
      {children}
    </AuthContext.Provider>
  );
};
Add a comment

Leave a Reply

Keep Up to Date with the Most Important News

By pressing the Subscribe button, you confirm that you have read and are agreeing to our Privacy Policy and Terms of Use

Discover more from Dev solutions

Subscribe now to keep reading and get access to the full archive.

Continue reading