Hello guys so I have the following problem:
I have a login form after user successfully provide the right info for signing in, I store the user object and access token in the AuthContext
I protect the home route using the context
Problem => the react state inside the context is not being updated
-[Edit] Solution => I found the solution and it was only changing the following code: const {setAuth} = useAuth(); to the code: const {setAuth} = useAuth({});
-[Edit 2] => Because I am a beginner I also discovered that navigation between components with anchor tag () or window location cause the lose of state data so I should use Link from react router dom to avoid re-rendering
AuthProvider.js
import { createContext, useState } from "react";
const AuthContext = createContext({});
export const AuthProvider = ({ children }) => {
const [auth, setAuth] = useState({});
return (
<AuthContext.Provider value={{ auth, setAuth }}>
{children}
</AuthContext.Provider>
)
}
export default AuthContext;
App.js
function App() {
return (
<Routes>
<Route path="/" element={<Layout />}>
{/* public routes */}
<Route path="auth" element={<AuthLayout />}>
<Route path="login" element={<Login />} />
<Route path="register" element={<Register />} />
<Route path="unauthorized" element={<Unauthorized />} />
</Route>
{/* we want to protect the following routes */}
{/* RequireAuth having outlet => return child only if context auth has user object */}
<Route element={<RequireAuth />}>
<Route path="home" element={<Home />} />
</Route>
{/* catch all */}
</Route>
</Routes>
);
}
export default App;
RequireAuth.js [ Problem is here, the auth is always empty]
const RequireAuth = () => {
const { auth } = useAuth();
const location = useLocation();
return auth?.userObject ? (
// we used from location and replace so we want to save the previous location of the visited page by user so he is able to go back to it
<Outlet />
) : (
<Navigate to="/auth/login" state={{ from: location }} replace />
);
};
export default RequireAuth;
Login.js [Here I update the state]
const handleFormSubmission = async (data,e) => {
e.preventDefault();
try {
const response = await axios.post(
ApiConstants.LOGIN_ENDPOINT,
JSON.stringify({
Email: email,
Password: password,
}),
{
headers: ApiConstants.CONTENT_TYPE_POST_REQUEST,
}
);
//const roles = ;
const userObject = response?.data;
const accessToken = response?.data?.token;
setAuth({ userObject, password, accessToken });
console.log(userObject);
console.log(accessToken);
console.log(password);
message.success("You are successfully logged in");
index.js
import React from "react";
import ReactDOM from "react-dom/client";
import App from "./App";
import { BrowserRouter, Routes, Route } from "react-router-dom";
import { AuthProvider } from "./context/AuthProvider";
import "./styles/ant-design/antd.css";
const root = ReactDOM.createRoot(document.getElementById("root"));
root.render(
<React.StrictMode>
<BrowserRouter>
<AuthProvider>
<Routes>
<Route path="/*" element={<App />} />
</Routes>
</AuthProvider>
</BrowserRouter>
</React.StrictMode>
);
CodePudding user response:
Did you import setAuth correctly? Did you call setAuth({}) inside handleFormSubmission function?
CodePudding user response:
I have gone through the code and there are few suggestions which will make code work.
import { createContext, useState } from "react";
const AuthContext = createContext({});
export const AuthProvider = ({ children }) => {
const [auth, setAuth] = useState({});
function updateAuth(authVal) {
console.log("update auth called with value", authVal);
setAuth(authVal);
}
return (
<AuthContext.Provider value={{ auth, updateAuth }}>
{children}
</AuthContext.Provider>
);
};
export default AuthContext;
Also we need few changes in the consumer code which looks like below
const { updateAuth } = useContext(AuthContext);
const handleFormSubmission = async (e) => {
e.preventDefault();
try {
const response = await axios.get("https://catfact.ninja/breeds?
limit=1");
//const roles = ;
const userObject = response?.data;
console.log("cats api data response is ", userObject);
updateAuth(userObject);
//setAuth({ userObject, password, accessToken });
} catch (err) {
console.error("some error");
}
};
I have made sample application on codesandbox for the same as well. Please find url as https://codesandbox.io/s/funny-scott-n7tmxs?file=/src/App.js:203-689
I hope this help and have a wonderful day :)