1
// auth provider
import React from "react";
import { useState } from "react";
import { useSelector } from "react-redux";
import { Navigate, useLocation } from "react-router-dom";

export const AuthContext = React.createContext();
export const AuthProvider = ({ children }) => {
  const currentUser = useSelector((state) => state.userData.user);
  const location = useLocation();

  if (!currentUser)
    return (
      <Navigate to="/signIn" replace state={{ path: location.pathname }} />
    );

  return (
    <AuthContext.Provider value={currentUser}>{children}</AuthContext.Provider>
  );
};
//main.jsx
ReactDOM.createRoot(document.getElementById('root')).render(
  <React.StrictMode>
      <Provider store={store}>
        <BrowserRouter>
          <Routes>
            <Route path='/signIn' element={<GoogleSignIn />} />
            <Route path='*' element={<App />}/>
          </Routes>
        </BrowserRouter>
      </Provider>
  </React.StrictMode>
)
// app.jsx
<div className="App grid">
  <AuthProvider>
     <Navbar />
     <Routes>
       <Route path="channels" element={<UserChannels />} />
       <Route path="/channel/new" element={<CreateChannel />} />
       <Route path="/channel/:channelID" element={<Channel />} />
     </Routes>
  </AuthProvider>
</div>

I want to have protected routes so, only when user is logged in they can go to these routes else they must be redirected to signIn page

Storing user info as redux state

useSelector returns null immediately so the page navigates to signIn page

skyboyer
  • 22,209
  • 7
  • 57
  • 64
  • Does the useSelector return null even when user is defined? I assume at some point your user object is getting cleared and assigned again. – Oshan Abeykoon Oct 01 '22 at 12:00
  • yes after login it is defined for the location that caused navigation to `signIn` page to but after reloading the page it is again `null` – Peter Austin Oct 01 '22 at 12:04
  • If you refresh the browser it will be null again, since entire redux state get re created. – Oshan Abeykoon Oct 01 '22 at 12:26
  • Please clarify your specific problem or provide additional details to highlight exactly what you need. As it's currently written, it's hard to tell exactly what you're asking. – Community Oct 01 '22 at 13:13

1 Answers1

4

For the first time rendering, the useSelector will always return a default value of userData.user, then you can fill it with user data that you get from API call in your app. You might need to add isLoadingUser in your store.

export const AuthProvider = ({ children }) => {
  const {user: currentUser, isLoadingUser} = useSelector((state) => state.userData);
  const location = useLocation();

  if(isLoadingUser){
    return <LoadingPage/>
  }

  if (!currentUser && !isLoadingUser)
    return (
      <Navigate to="/signIn" replace state={{ path: location.pathname }} />
    );

  return (
    <AuthContext.Provider value={currentUser}>{children}</AuthContext.Provider>
  );
};
aldhyyy
  • 81
  • 2