Why does my object return null in the first render and send null data through react router[v6]?

Viewed 27

as the title clearly states, im just having some issues with sending user data to profile page through react router v6, but even though currentUser state gets populated after i set them based on the conditions(logged in, user found, user not found), it wont send the data in that state to the Profile page, this kinda seems to be an issue relying on render counts, but it should still send the data exactly to profile page in case the conditions are met, when user credentials are correct... tried to keep it pretty simple decreasing the functions count used in the logic but still something goes wrong...im very stuck, any help is kindly appreciated..

final case:

https://codesandbox.io/s/heuristic-mendel-syxlol?file=/src/index.js


import { Route, Routes, Link} from "react-router-dom";
import Home from "./pages/Home";
import Login from "./pages/Login";
import Profile from "./pages/Profile";
import { useNavigate } from "react-router-dom";
import { useCallback, useEffect, useRef} from 'react';
import {useState} from 'react'
import {useMemo} from  'react';

function App() {

const [userInput, setUserInput] = useState("");
const [passInput, setPassInput] = useState("");
const [isLoggedin, setIsLoggedin] = useState(false);

const [error, setError] = useState(false);

  const navigate = useNavigate();

  const data = [
    { id: 1, username: "jane", password: "1234",isAdmin:true },
    { id: 2, username: "jack", password: "1234", isAdmin: false },
    { id: 3, username: "john", password: "1234" , isAdmin:false},
    { id: 4, username: "elizabeth", password: "1234", isAdmin: false}
  ];

const currentUser = {id:null, username:null, password:null, isAdmin:null};



  const loginCheck = (username, password) => {

    username = userInput.trim();
    password = passInput.trim();

    console.log("logincheck function working");
    const userData = (userid,userpass) => data.find(user => user.username === userid && user.password === userpass);  
     
       const getUserData = userData(username,password);
      
       if (getUserData !== undefined && getUserData !== null) {
         console.log("user found");
         setIsLoggedin(true);
          currentUser.id = getUserData.id;
          currentUser.username = getUserData.username;
          currentUser.isAdmin = getUserData.isAdmin;
          
         setError(false);
         console.log(currentUser);
       }
       else {
          console.log("user not found");

          setError(true);
          setIsLoggedin(false); 
          console.log(currentUser);

        }     
   };

   useEffect(() => {

   if (isLoggedin) {
    console.log(currentUser);

    return navigate(`users/${currentUser.username}`);
  }

    }, [isLoggedin])
  

  return (
    <div>
      
      <input name = "username" type = "text"  placeholder = "username" onChange={(e)=> setUserInput(e.target.value)}  /> 
      <input name = "password" type = "password"  placeholder = "password" onChange={(e)=> setPassInput(e.target.value)}/>
      <button onClick = {loginCheck} type = "submit">Login</button>
<div style = {{display:"flex",flexDirection:"column",justifyContent:"center",alignItems:"center"}}>
  <h1>
<label>log in to your account</label>

  </h1><br/>
<div>

{error && <div><h1>The username or password provided were incorrect.</h1></div>}

</div>
  
 

</div>
      <Routes>
        <Route path="/" element={<Home />} />
        <Route path="login" element={<Login />} />
        <Route path="users/:id" element={<Profile data = {currentUser}/>} />
          
        <Route path="*" element={<h1>404 not found</h1>} />
      </Routes>
    </div>
  );
}

export default App;


1 Answers

The final case you have linked to is different from the code you have pasted here. I'm going to refer to the linked code.

This is a classic case of rushing to use the state before it's updated. You set the current user here:

setCurrentUser({
        id: gelen?.id,
        username: gelen?.username,
        password: gelen?.password
      });

And in the very next line you call the navigateAfterLogin(), which runs this check: currentUser.id && currentUser.username && currentUser.password. By the time this check runs, the state is most likely at the initial state with all null values.

If you want to make sure that the state is current before navigating, one option is to use useEffect.

useEffect(() => {
    if (currentUser.id && currentUser.username && currentUser.password) {
        navigateAfterLogin();
    }
}, [currentUser.id, currentUser.username, currentUser.password]);

Checking one of the 3 fields will do just as well, since you're setting them all in one place together.

Also, when you update state variables that hold objects, it is recommended not to mutate them directly.

setCurrentUser(prevCurrentUser => {
    return {
        ...prevCurrentUser,
        id: gelen?.id,
        username: gelen?.username,
        password: gelen?.password
    }
}
Related