DEV Community

Muhammet Fatih Gul
Muhammet Fatih Gul

Posted on

React useNavigate faster than useContext

I'm making a website using React, Nodejs, Expressjs and Mysql. It has a login, register and profile pages. When I logged in I'm redirecting users with useNavigate to the profile page. Profile page shows the user email.

But when I navigate users to Profile, in the first display, Profile page is not showing user email. I have to refresh to page to see email.

I'm using useContext and wrapped all application with Provider. There's no problem. But when i navigate to Profile, useContext working a little bit late and it's not changing state instantly. Is there a way to solve this?

Top comments (8)

Collapse
 
lalami profile image
Salah Eddine Lalami

@ IDURAR , we use react context api for all UI parts , and we keep our data layer inside redux .

Here Article about : πŸš€ Mastering Advanced Complex React useContext with useReducer ⭐ (Redux like Style) ⭐ : dev.to/idurar/mastering-advanced-c...


Mastering Advanced Complex React useContext with useReducer (Redux like Style)

Collapse
 
jacobgavin profile image
Jacob Gavin

Its hard to give help with no codesandbox.io example. Have you checked that you update the state of the user before you do the redirect?

Collapse
 
mfatihgul profile image
Muhammet Fatih Gul • Edited

I'm using backend too. So, i don't know if i can use Codesandbox to show my issue. I'll share some codes to indicate my issue

This is my Login page. I'm using "useContext". I created a useEffect to see if user already logged in. authState.status is checking if there's a cookie in the browser in the backend.

When I click "Login button". loginUser() function is working. This function is creating new user. If there's not an error, it changes the state and creating a session. After that its navigate to profile

function Login() {
  let navigate = useNavigate();
  const [email, setEmail] = useState("");
  const [password, setPassword] = useState("");

  //Context
  const { authState, setAuthState } = useContext(AuthContext);

  console.log(authState.status);
  useEffect(() => {
    if (authState.status == true) {
      navigate("/profile");
    }
  }, []);

  // const [loginStatus, setLoginStatus] = useState("");

  Axios.defaults.withCredentials = true;

  const loginUser = () => {
    Axios.post("http://localhost:3001/login", {
      email: email,
      password: password,
    }).then((response) => {
      if (response.data.message) {
        console.log(response.data.message);
      } else {
        setAuthState({
          email: response.data.email,
          id: response.data.id,
          status: true,
        });
        navigate("/profile");
      }
    });
  };
  return (

Enter fullscreen mode Exit fullscreen mode

This is my App.js. In useEffect, I'm making a get request to /login to checking if there's a cookie in the browser in the backend. app.post and app.get are totally different things in the backend

function App() {
  const [authState, setAuthState] = useState({
    email: "",
    id: 0,
    status: false,
  });

  useEffect(() => {
    Axios.get("http://localhost:3001/login", { withCredentials: true }).then(
      (response) => {
        console.log(response);
        if (response.data.message) {
          setAuthState({ ...authState, status: false });
          console.log(response.data.message);
        } else {
          setAuthState({
            email: response.data[0].email,
            id: response.data[0].id,
            status: true,
          });
          console.log("I'm here");
        }
      }
    );
  }, []);

  return (
Enter fullscreen mode Exit fullscreen mode

this is app.get

app.get("/login", (req, res) => {
  if (req.session.user) {
    // res.send({ user: req.session.user });
    res.json(req.session.user);
  } else {
    res.send({ message: "It's Empty" });
  }
});
Enter fullscreen mode Exit fullscreen mode

I'm sorry if it is too much ask :(

My issue is. When i go to Profile in the first time. I have to refresh the page to see the email from the context

Collapse
 
jacobgavin profile image
Jacob Gavin

In you App.js you aren't setting the same auth state as you do in you Login component. It seems that you have missunderstood the concept of context a bit. Or there are some important bits of code missing here. You need to create a "AuthProvider" that stores your context. And you can handle the login and the "check auth cookie" request in that Provider instead of doing it in different parts of the app.

I can't really point you in the right correction based on this. I recommend reading kentcdodds.com/blog/authentication... to get some understanding of how it can be done.

Is your app.get("/login", ...) function only returning what got passed in req.session.user or have you stripped out some logic there?

Also this useEffect needs to have authState.status in its dependency array like this:

  useEffect(() => {
    if (authState.status == true) {
      navigate("/profile");
    }
  }, [authState.status]);
Enter fullscreen mode Exit fullscreen mode

otherwise it will only check that status on initial render. You can read about it here reactjs.org/docs/hooks-reference.h...

Thread Thread
 
mfatihgul profile image
Muhammet Fatih Gul

Yess. I already have an AuthContext.Provider in App.js and I imported it

<div className="App">
      <AuthContext.Provider value={{ authState, setAuthState }}>
        <Router>
          <Header />
          <Routes>
            <Route exact path="/" element={<Mainpage />} />
            <Route exact path="/login" element={<Login />} />
            <Route exact path="/register" element={<Register />} />
            <Route path="/profile" element={<Profile />} />
            <Route path="/courses" />
          </Routes>
        </Router>
      </AuthContext.Provider>
    </div>
Enter fullscreen mode Exit fullscreen mode

app.get is just returning req.session.user. I created it in app.post('/login'). Here it is

app.post("/login", (req, res) => {
  const email = req.body.email;
  const password = req.body.password;

  db.query("SELECT * FROM users WHERE email = ?;", email, (err, result) => {
    if (err) {
      res.send({ err: err });
    }

    if (result.length > 0) {
      bcrypt.compare(password, result[0].password, (error, response) => {
        if (response) {
          req.session.user = result;
          // console.log("hello: " + req.session.user);
          res.send(result);
        } else {
          res.send({ message: "Wrong username/password combination!" });
        }
      });
    } else {
      res.send({ message: "User doesn't exist" });
    }
  });
});
Enter fullscreen mode Exit fullscreen mode

Thank you for the tips and the sources. I will check immediately

Collapse
 
abouzeyd profile image
mouhamed

hello please i'm new in react.js and i work on a website who allow to listen audio.but when i play one audio all audios begin to play i want.
how solve this issue thank you.

Collapse
 
mfatihgul profile image
Muhammet Fatih Gul

Hello. I never work with audios. Sorry. But you can create a post that has this tags. #help #react

Collapse
 
abouzeyd profile image
mouhamed

Thank you for your answer