1

I have a problem now because it won't navigate me after I click log in, it takes cookies, but won't relocate. You can show my components look right now. Everything is fine, except when I click log in, it won't relocates me to the home page.

Components:

<App /> component

function App() {
 const [userData, setUserData] = useState();
 const [login, setLogin] = useState()

  return (
  <div className="App">
    <Router>
      <Routes>
      <Route element={<PrivateRoutes login={login}  userData= 
      {userData} />}>
        <Route element={<Home />} path="/" exact />
        <Route element={<Products />} path="/products" />
      </Route>
      <Route element={<Login setUserData={setUserData} setLogin= 
      {setLogin} />} 
      path="/login" />
    </Routes>
  </Router>
  </div>
 );
 }

<Login /> component

const Login = ({ setUserData }) => {
const [username, setUsername] = useState("");
const [password, setPassword] = useState("");

const [checking, setChecking] = useState(true)
const [loginStatus, setLoginStatus] = useState("");

Axios.defaults.withCredentials = true;

  const login = (e) => {
e.preventDefault();
Axios.post("http://localhost:3001/login", {
  username: username,
  password: password,
}).then((response) => {
  setUserData(response.data);
  navigate("/");
});

};

useEffect(() => {
  if (userData?.loggedIn) {
    navigate("/");
  }
   }, [userData]);

}

return (
<div>
  <div>Prijava</div>
  <div>
    <form onSubmit={login}>
      <label>Korisničko ime</label>
      <input
        type="text"
        onChange={(e) => {
          setUsername(e.target.value);
        }}
      />
      <label>Lozinka</label>
      <input
        type="password"
        onChange={(e) => {
          setPassword(e.target.value);
        }}
      ></input>
      <button>Prijavi se</button>
    </form>
  </div>
  </div>
  );
  };

<PrivateRoutes /> component

const PrivateRoutes = ({userData, login}) => {


 return !login ? <p>Checking...</p>: userData?.loggedIn ? <Outlet 
 /> : <Navigate to="/login" />;    

  };

Console log error, after implementing code.

enter image description here

Newest App and PrivateRoutes version

enter image description here

2 Answers2

0

When the page loads, userData is not set, because the useEffect runs after the JSX is rendered. Hence your condition is falling to <Navigate to="/login" /> instead of <Outlet/>.

You could use an additional state, called checking, for example, use it to display some loading message while the data is fetched.

Also, move the useEffect to check the login state on load inside PrivateRoutes. Changes your components as follows.

App:

function App() {
  const [userData, setUserData] = useState();
  const [checking, setChecking] = useState(true);

  useEffect(() => {
    Axios.get("http://localhost:3001/login")
      .then((response) => {
        if (response.data.loggedIn == true) {
          setUserData(response.data);
        }
        return;
      })
      .catch((error) => {
        console.log(error);
      })
      .finally(() => {
        setChecking(false);
      });
  }, []);

  return (
    <div className="App">
      <Router>
        <Routes>
          <Route element={<PrivateRoutes userData={userData} checking={checking} />}>
            <Route element={<Home />} path="/" exact />
            <Route element={<Products />} path="/products" />
          </Route>
          <Route element={<Login setUserData={setUserData} userData={userData} />} path="/login" />
        </Routes>
      </Router>
    </div>
  );
}

PrivateRoutes:

const PrivateRoutes = ({ userData, checking }) => {
  return checking ? <p>Checking...</p> : userData?.loggedIn ? <Outlet /> : <Navigate to="/login" />;
};

Login:

import { useNavigate } from "react-router-dom";

const Login = ({ setUserData, userData }) => {
  const [username, setUsername] = useState("");
  const [password, setPassword] = useState("");
  const navigate = useNavigate();

  Axios.defaults.withCredentials = true;

  const login = (e) => {
    e.preventDefault();
    Axios.post("http://localhost:3001/login", {
      username: username,
      password: password,
    }).then((response) => {
      setUserData(response.data);
    });
  };

  useEffect(() => {
    if (userData) {
     navigate("/");
    }
  }, [userData]);

  return (
    <div>
      <form>
        <div>Prijava</div>
        <div>
          <form onSubmit={login}>
            <label>Korisničko ime</label>
            <input
              type="text"
              onChange={(e) => {
                setUsername(e.target.value);
              }}
            />
            <label>Lozinka</label>
            <input
              type="password"
              onChange={(e) => {
                setPassword(e.target.value);
              }}
            ></input>
            <button>Prijavi se</button>
          </form>
        </div>
      </form>
    </div>
  );
};
Youssouf Oumar
  • 29,373
  • 11
  • 46
  • 65
0

To resolve the issue with the userData state being undefined during the initial render, you can initialize it with a default value in the state declaration, for example:

const [userData, setUserData] = useState({ loggedIn: false });

Additionally, you can wrap the conditional rendering in a useEffect hook that depends on userData:

useEffect(() => {
  if (userData?.loggedIn) {
    // Render the Outlet component
  } else {
    // Render the Navigate component
  }
}, [userData]);