3

I lately noticed that calling useSelector in a react-redux is a bit delayed. Now i am using useEffect to check if the state is a certain value. like so:

const user= useSelector(state=>state.user.value);
useEffect(()=>{
   if (!user){
      alert('You have to login to see this page');
      //Redirect the visitor to the login page
   }

},[]);

I noticed that useEffect runs before useSelector fetch the data from the state and finds the user null so it displayes the message and redirects the user while I have a user in the state. By the way I am also using redux-persist middle-ware to store the state in the localStorage

I tried to delay the logic inside useEffect like so:

useEffect(()=>{
 setTimeout(() => {
    if (!user){
       alert('You have to login to see this page');
       //Redirect the visitor to the login page
    }
 },10000);
},[]);

But still it does not work as it takes the same null user that it came with in the the beginning of loading the page!!

I put this code to watch the user change:

useEffect(() => {
        console.log('At: ' + new Date(Date.now()).toLocaleString().split(',')[1] + ' user is:', user);
}, [user]);

And this is a screen shot of the console:
console log for the snippet above

Any hints on how to bypass this problem? Or may be I am doing something wrong?

Arkellys
  • 5,562
  • 2
  • 16
  • 40
Shangab
  • 39
  • 1
  • 9

3 Answers3

2

user should be a dependency of the useEffect as it's used inside

useEffect(()=>{
   if (!user){
      alert('You have to login to see this page');
      //Redirect the visitor to the login page
   }

},[user]);

Then when the user change it will re-run your useEffect

Julien Kode
  • 5,010
  • 21
  • 36
1

Or may be I am doing something wrong?

Yes, if you want to redirect the user somewhere after finding out that they're not logged in, you need to explicitly model this state, which is something like "auth pending" or "initializing auth". You simply don't know yet wether the user is authenticated or not, since this is potentially an async operation you need to wait for. Handling this third state explicitly (with an initial state in redux that reflects that) solves your issue. The selector returning null or an empty object does not tell you wether it's already confirmed that they're logged out.

timotgl
  • 2,865
  • 1
  • 9
  • 19
  • You seem very right @timotgl, I will do this and may definetly mark your asnwer as a solver. Thanks a lot. But this also happens while the user is logged in already and I see the state in redux devtool filled with a user. But the page that needs the user to be there do this login that I show in question !! mmm, – Shangab Aug 08 '22 at 13:12
-1

As @Arkellys suggested using the react hook useLayoutEffect seems to wait for all hooks to complete unlike useEffect and problem is solved.

As of your question @Julien the way you setup redux-persist is as follows:

  1. install the package like so: npm i redux-persist
  2. Use it as middle where when configuting the store like so:
const totalReducer = combineReducers({
    reduser1: reducer1Reducer,
    ...etc    
})
const persistedReducer = persistReducer({
    key: 'root',
    storage,
    transforms: process.env.NODE_ENV === 'production' ? [
        encryptTransform({
            secretKey: process.env.REACT_APP_CRPKEY, onError: (error) => {
                console.log('Erorr in Encryption: ', error);
            }
        })
    ] : [],

}, totalReducer);

Then you use the persistedReducer as your reducers in the store configuration. Here also I am using encryption only if I am in production.

All the best.

Shangab
  • 39
  • 1
  • 9