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.
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.
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>
);
};