Navbar does not hold login state because it's not a child of the AuthProvider

160 Views Asked by At

I am having an issue with my app not holding the login state. I have created a react-router Outlet for my navbar because I didn't want my navbar to show on the landing page.

Then I created an AuthProvider component that would hold and pass the login state to its children.

I am able to log in using my AuthButton on my navbar but it won't hold the login state. Whenever I refresh the page or navigate to a different page I will get logged out and will need to log in again.

My assumption is that, in my App.js file, I am wrapping my navbar around most routes including my protected routes which are wrapped with the RequireAuth component thus not passing the login state or holding it.

AuthProvider.js

const AuthContext = createContext({});

export const AuthProvider = ({ children }) => {
  const [auth, setAuth] = useState({});

  return (
    <AuthContext.Provider value={{auth, setAuth}}>
      { children }
    </AuthContext.Provider>
  );
}

export default AuthContext;

RequireAuth.js

const RequireAuth = () => {
  const { auth } = useAuth();
  const location = useLocation();

  return (
    auth?.user
      ? <Outlet />
      : <Navigate to="/login" state={{ from: location }} replace />
  );
}

AuthButton.js

const AuthButton = () => {
  const { auth } = useAuth();
  const loggedIn = auth?.user;

  return (
    loggedIn
      ? <LogoutButton />
      : <LoginButton />
  );
}

App.js

function App() {
  return (
    <Routes>
      <Route exact path="/" element={<Landing />} />

      <Route element={ <WithNav /> } >
        {/*--Public--*/}
        <Route path="/login" element={<LoginForm />} />
        <Route path="/about" element={<AboutMe />} />

        <Route path="/blogs" element={ <ShowBlogList />} />
        <Route path="/blogs/:id" element={ <ShowBlogDetails /> }/>

        <Route path="/projects" element={ <ShowProjectList />} />
        <Route path="/projects/:id" element={ <ShowProjectDetails /> }/>

        {/*--Protected--*/}
        <Route element={<RequireAuth />}>
          <Route path="/blogs/new" element={<CreateBlog />} />
          <Route path="/blogs/:id/edit" element={ <UpdateBlogInfo /> }  />
          <Route path="/blogs/:id/delete" />

          <Route path="/projects/new" element={<CreateProject />} />
          <Route path="/projects/:id/edit" element={ <UpdateProjectInfo /> }  />
          <Route path="/projects/:id/delete" />
        </Route>
      </Route>
    </Routes>
  );
}

export default App;

1

There are 1 best solutions below

1
Rittika Dev On

You can keep the Nav component outside Routes if it is being rendered in each page.

And to see if a user is logged in, in Nav write down,

 const [user] = useAuthState(auth);

    return(
          {
            user ? 
              <button className='btn btn-link text-white text-decoration-none'>
               Sign Out</button>
             :
               <Nav.Link to="login"> Login </Nav.Link>
           }
     )

You do not have to keep the Nav component inside RequireAuth