0

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

2
  • Hi Ahmed, i think we need to wrap our components wrapped inside the AuthContext provider which is missing in this case. Commented Oct 2, 2022 at 11:35
  • @HemantKumar sorry forget to mention that I edited the post, I already did inside the index.js Commented Oct 2, 2022 at 11:37

2 Answers 2

0

Did you import setAuth correctly? Did you call setAuth({}) inside handleFormSubmission function?

Sign up to request clarification or add additional context in comments.

6 Comments

Hi Arifur, please ask your questions in the comment section of OP's question.
Sorry, I don't have enough reputation to comment everywhere.
at the the top of the Login component I wrote the following code: const {setAuth} = useAuth();
Before handleFormSubmission function you have to write const {setAuth} = useContext( AuthContext). useContex and AuthContext have to import.
From AuthProvider.js you have to export AuthContext
|
0

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 :)

1 Comment

I really appreciate your comment and the details the solution was only changing the following code: const {setAuth} = useAuth(); to the code: const {setAuth} = useAuth({}); Hope you have a wonderful day too, Thanks.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.