0

I have a React/Node application which let the user login and get redirected to his dashboard. What I want to achieve is to prevent the user from going to the other pages if he is not logged in. My App.js looks like this :

function App() {
  const userInfo = localStorage.getItem("userInfo");
  let resultat = JSON.parse(userInfo);

  if(resultat!==null){
    if(resultat.status==="ok"){
      return (
        <>
        <Router basename={process.env.PUBLIC_URL}>
          <Switch>
            <Route path='/' exact component={ Dashboard }>
            </Route>
            <Route path='/login' exact component={ Login }>
            </Route>
            <Route path='/dashboard' exact component={ Dashboard }>
            </Route>
            <Route path='/other_route' exact component={ OtherComponent }>
            </Route>
          </Switch>
        </Router>
        </>
      );
    } else {
      return(
        <>
        <Router basename={process.env.PUBLIC_URL}>
          <Switch>
            <Route path='/' exact component={ Login }>
            </Route>
            <Route path='/login' exact component={ Login }>
            </Route>
            <Route path='/*' exact>
              <>
                You are not logged in. To see this page please, log in.
              </>
            </Route>
          </Switch>
        </Router>
        </>
      );
    }
  } else {
      return(
        <>
        <Router basename={process.env.PUBLIC_URL}>
          <Switch>
            <Route path='/' exact component={ Login }>
            </Route>
            <Route path='/login' exact component={ Login }>
            </Route>
            <Route path='/*' exact>
              <>
                You are not logged in. To see this page please, log in.
              </>
            </Route>
          </Switch>
        </Router>
        </>
      );
    }
}

My Login.js component redirects the user to the path /dashboard if the login process is successful. The problem is that it still loads the page that says to go to the login. If I reload the page though, it shows the actual dashboard.

I happens because (I guess) React just switches between the routes, from /login to /* (/dashboard) but it doesn't rerun the App() function so it can't redo the if(resultat!==null) test.

I figured that if I tried to force React to reload the page while going to the dashboard (I tried this answer) but it didn't work.

Is there any way to achieve what I want to do ?

Thanks in advance.

mqbaka mqbaka
  • 235
  • 1
  • 7
  • 1
    You need to change the variable to a state via useState or state if you use a class component. React does only rerender components that really changed. If a variable changes and you want to rerender components referencing those you need a state. – SemmelJochen Oct 21 '21 at 11:37
  • @FeedThePiano Thank you. Could you show me a good way to do that, though ? I created a state where I stored `resultat` but I don't know how to update that state when the routes are switching. – mqbaka mqbaka Oct 21 '21 at 12:05
  • 1
    Sorry for the late answer. In your case, you are using a functional component and therefore need to define and update the state as follows: `const [userInfo, setUserInfo] = useState({someData});` with userInfo you access the data and with setUserInfo you update the data. Its important to update it with the setUserInfo Method. Otherwise, the rerender will not be triggered and it's not clean to change the state otherwise. You can read more right here: https://reactjs.org/docs/hooks-state.html Hope this helps – SemmelJochen Oct 28 '21 at 21:31
  • Thank you for your help, the problem was that even if I put `userInfo` in a state, my `` did not update it, so I thought about using `react-redux` and it worked ! – mqbaka mqbaka Nov 05 '21 at 05:41

1 Answers1

0

Thanks to @FeedThePiano' s help, I was able to figure it out.

The problem was that, even if I used a state for storing userInfo the state wasn't updated when the user logs in (since the login process happens in the <Login/> component). So I needed to somewhat find a way to update the state from the <Login/> component.

react-redux offers a way to do that and here is how I did it :

-I created a reducer, Reducers\signInReducer.js:

const initialState= {
    isSignedIn: false
}

export default function signInReducer(state= initialState, action){
    switch(action.type){
        case "LOGIN":
            return{
                ...state,
                isSignedIn: true
            }
        case "LOGOUT":
            return{
                ...state,
                isSignedIn: false
            }
        default:
            return(state);
      }
}

-I used Reducers\index.js to combine it with my other reducers:

import { combineReducers } from "redux";
import otherReducer from "./path/to/other/reducer";
import signInReducer from "./signInReducer";

const allReducers = combineReducers({otherReducer, signInReducer});

export default allReducers;

-Then in my Login.js I added:

import React, {useRef, useState} from 'react';
import { useDispatch } from 'react-redux';

export default function login(){
    const dispatch= useDispatch();
    //Code for the login process
    //Login is done..
    dispatch({
        type: "LOGIN"
    });
    //We can now redirect (safely)
    //Code for redirection
}

-Then I just need to update my state in the App.js:

import {useState, useEffect} from 'react';
import { useSelector, useDispatch } from 'react-redux';
//import the components..
function App() {
    const [isUserLoggedIn, setUserLoggedIn]= useState(false);
    const [userInfo, setUserInfo]= useState(null);
    const isLogged= useSelector(state => state.signInReducer);
    useEffect(()=> {
        let info= localStorage.getItem("userInfo");
        let parsedInfo= JSON.parse(info);
        if(parsedInfo!== null){
            setUserInfo(parsedInfo.data);
        }
    },[]);

    useEffect(()=> {
        if(isLogged.isSignedIn){
            setUserLoggedIn(true);
        } else {
            setUserLoggedIn(false);
        }
    },[isLogged]);

    useEffect(()=> {
        if(userInfo!== null){
            setUserLoggedIn(true);
        } else {
            setUserLoggedIn(false);
        }
    }, [userInfo]);

    if(isUserLoggedIn){
        return (
            <>
            <Router basename={process.env.PUBLIC_URL}>
              <Switch>
                <Route path='/' exact component={ Dashboard }>
                </Route>
                <Route path='/login' exact component={ Login }>
                </Route>
                <Route path='/dashboard' exact component={ Dashboard }>
                </Route>
                <Route path='/other_route' exact component={ OtherComponent }>
                </Route>
              </Switch>
             </Router>
            </>
          );
    } else {
        return(
          <>
          <Router basename={process.env.PUBLIC_URL}>
            <Switch>
              <Route path='/' exact component={ Login }>
              </Route>
              <Route path='/login' exact component={ Login }>
              </Route>
              <Route path='/*' exact>
                <>
                  You are not logged in. To see this page please, log in.
                </>
              </Route>
            </Switch>
          </Router>
          </>
        );
    }
}

This way, the userInfo state gets update on time and the redirection works with no problem.

mqbaka mqbaka
  • 235
  • 1
  • 7