1
votes

I'm setting up a basic authentication system with React and while signup and login actions correctly redirect and render the appropriate components, my logout action redirects to the protected route and renders the associated component, even though the authentication variable managed with the context API is successfully updated when logging out. The whole operation works in the end, as when I'm refreshing the page, I am successfully redirected to my login page.

I'm using Node.js to manage my sessions and dispatching the logout action works well as, as I said, the variable used with the Context API is updated. I'm using the Effect Hook on my Header component where the logout is initiated and I can see the auth variable being changed.

Here is my code:

AppRouter.js

export const history = createBrowserHistory();

const AppRouter = () => (
  <Router history={history}>
    <Switch>
      <PublicRoute path="/" component={AuthPage} exact={true} />
      <PrivateRoute path="/dashboard" component={DashboardPage} />
      <Route component={NotFoundPage} />
    </Switch>
  </Router>
);

PublicRoute.js

const PublicRoute = ({ component: Component, ...rest }) => {

  const { uid } = useContext(AuthContext);

  useEffect(() => {
    console.log("Public Route - Variable set to:", uid);
  }, [uid])

  return (
    <Route
      render={props =>
        uid !== undefined ? (
          <Redirect to="/dashboard" />
        ) : (
          <Component {...props}/>
        )
      }
      {...rest}
    />
  )
};

PrivateRoute.js

const PrivateRoute = ({ component: Component, ...rest }) => {

  const { uid } = useContext(AuthContext);

  useEffect(() => {
    console.log("Private Route - Variable set to:", uid);
  }, [uid])

  return (
    <Route
      render={props =>
        uid !== undefined ? (
          <div>
            <Header />
            <Component {...props}/>
          </div>
        ) : (
          <Redirect to="/" />
        )
      }
      {...rest}
    />
  )
};

Header.js

export const Header = () => {

  const { uid, dispatch } = useContext(AuthContext);

  useEffect(() => {
    console.log("Header - Variable set to:", uid);
    // console.log("HIST", history);
  }, [uid])

  const logout = async () => {

    const result = await startLogout();

    if (result.type !== undefined) {
      dispatch(result); // Works well
      // window.location.href = '/';
      // history.push('/');
      history.replace('/');
    } else {
      console.log(result);
    }
  }

  return (
    <header className="header">
      <div className="container">
        <div className="header__content">
          <Link className="header__title" to="/dashboard">
            <h1>A React App</h1>
          </Link>
          <button className="button button--link" onClick={logout}>Logout</button>
        </div>
      </div>
    </header>
  );
};

I tried both history.push('/') and history.replace('/'). Both these 2 methods work well as if I switch the path to an unknown route, my component that handles 404 is successfully rendered.

Below is my console output when I click the logout button. As you can see, the auth variable is well updated to undefined but that does not prevent my router to keep showing me the protected route. The router should not redirect me to the dashboard as my auth variable is set to undefined after logging out.

Header - Variable set to: {uid: undefined}
Private Route - Variable set to: {uid: undefined}
Public Route - Variable set to: {uid: undefined}
Header - Variable set to: {uid: undefined}
Private Route - Variable set to: {uid: undefined}

For the time being I'm using window.location.href = '/'; which works well, as it automatically reload the root page but I'd like to stick to react-router. Any thoughts? Thanks

1

1 Answers

0
votes

in the private route pass renders props.. like this:

const PrivateRoute = ({ component: Component, ...rest }) => {

  const { uid } = useContext(AuthContext);

  useEffect(() => {
    console.log("Private Route - Variable set to:", uid);
  }, [uid])

  return (
    <Route
      render={props =>
        uid !== undefined ? (
          <div>
            <Header {...props} />
            <Component {...props}/>
          </div>
        ) : (
          <Redirect to="/" />
        )
      }
      {...rest}
    />
  )
};

then in header use props to push history:

export const Header = (props) => {

  const { uid, dispatch } = useContext(AuthContext);

  useEffect(() => {
    console.log("Header - Variable set to:", uid);
    // console.log("HIST", history);
  }, [uid])

  const logout = async () => {

    const result = await startLogout();

    if (result.type !== undefined) {
      dispatch(result); // Works well
      // window.location.href = '/';
      // history.push('/');
      props.history.push('/');
    } else {
      console.log(result);
    }
  }