Search code examples
javascriptreactjsreduxreact-router-domuse-state

How to write dynamic routing in React?


I build an app in React and I try to make a dynamic routing, but my app doesn't wait for the useEffect to end.

What I want to do here is to send to my backend an object from localStorage, check it and send it back to frontend. If the result is true, when I type "/form" I want to go to "/form" route, but if is false I want to send him back to "/login".

I tried to use useState and a message while my useState is working but is not usefull...

When I'm logged in and I try to go to '/form', my app see that my useStates are false and redirect me to "/login" automatically and doesn't wait for my fetch to end...

How can I fix that?

import { BrowserRouter as Router, Route, Routes, Navigate } from 'react-router-dom';
import Login from './views/Login';
import Logout from './views/Logout';
import AddUser from './views/AddUser';
import Movies from './views/Movies';
import Table_data from './components/Table_data';
import NavbarMenu from './views/NavbarMenu';
import { useSelector, useDispatch } from 'react-redux';
import 'bootstrap/dist/css/bootstrap.min.css';
import './App.css';
import { useEffect, useState } from 'react';
import { globalRequestParameters, url } from './utils';


function App() {
  const dispatch = useDispatch();
  const data = useSelector((state) => state.users.data);
  const [loggedIn, setLoggedIn] = useState(false);
  const [finishedCheking, setFinishedChecking] = useState(false);

  useEffect(() => {
    if (!data.length) {
      let requestParameters = globalRequestParameters;
      fetch(url + 'users', requestParameters)
        .then(res => res.json()
          .then(res => {
            if (res.message) {
              dispatch({ type: 'setUsers', payload: res.data })
            }
          })
        )
    }

    if (localStorage.getItem('is_logged_in')) {
      let check_loggedIn = JSON.parse(localStorage.getItem('is_logged_in'));
      let requestParam = globalRequestParameters;
      requestParam.method = 'POST';
      requestParam.headers.Authorization = JSON.stringify(check_loggedIn);
      fetch(url + 'check', requestParam)
          .then(res => res.json()
              .then(res => {
                  if (res.loggedIn === true) {
                    setLoggedIn(true);
                    setFinishedChecking(true);
                  }
              })
          )
    }
      
  }, [])

  return (
    <div>
      <NavbarMenu />
      {finishedCheking === false ? 
        <div>Loading...</div>
        :
        loggedIn === false ? 
        <Router>
          <Routes>
            <Route exact path="/" element={<Table_data />} />
            <Route exact path="/login" element={<Login />} />
            <Route exact path="/logout" element={<Logout />} />
            <Route exact path="/form" element={<AddUser />} />
            <Route exact path="/movies" element={<Movies />} />
          </Routes>
        </Router>
        :
        <Router>
        <Routes>
          <Route exact path="/" element={<Table_data />} />
          <Route exact path="/login" element={<Login />} />
          <Route exact path="/logout" element={<Logout />} />
          <Route exact path="/form" element={<Navigate replace to="/login" />}/>
          <Route exact path="/movies" element={<Movies />} />
        </Routes>
      </Router>
      }
    </div>
  );
}

export default App;


Solution

  • Wrap both of your Routers with {finishedChecking === true ? {both routers} : <></>}. Inside promise .then change the value of finishedChecking to true. After change of state the jsx will be rendered once more and go inside the condition and you will be sure there that you have your promise resolved. If you need more than one condition then you can stack them up {finishedChecking === true && anotherVariable === true ? {both routers} : <> </>} and change them inside other promises.