Restricted navigation React Router Dom – Private and Public routes

  javascript, react-router-dom, reactjs, routes

I need to make a router system that distinguishes between authenticated and non-authenticated users.

What I want to achieve with this is that authed users can see their dashboard and personal details, but unauthed users can only see the landing page, the login form and the register form.

I currently have context management so I know whether a user is logged in or not. I just need to figure out all the redirects and routing related things.

My code is making all sorts of "strange" things. I don’t really know where I have messed it up.

AppContent.js

This is where all the routing happens.
AppLayout is just a layout wrapper with a header and a footer that must be visible only when logged in.

const AppContent = () => (
    <Router>
        <Switch>
            <PublicRoute component={() => (<h1>Landing page</h1>)} path='/' exact />
            <PublicRoute component={LoginPage} path='/login' exact />
            <PublicRoute component={() => (<h1>Register page</h1>)} path='/register' exact />

            <AppLayout>
                <PrivateRoute component={Home} path='/dashboard' exact />
                <PrivateRoute component={Demo} path='/demo' exact />
                <PrivateRoute component={Profile} path='/profile' exact />
            </AppLayout>

            <PublicRoute component={() => (<h1>not found</h1>)} path='*' />
            <PrivateRoute component={() => (<h1>not found</h1>)} path='*' />
        </Switch>
    </Router>
);

PublicRoute.js

const PublicRoute = ({ component: Component, ...rest }) => {
    const { user, isLoading } = useContext(AuthContext);

    if (isLoading) {
        return (
            <h1>Loading...</h1>
        );
    }

    return (
        <Route {...rest} render={(props) => (user ? <Redirect to='/dashboard' /> : <Component {...props} />)} />
    );
};

PrivateRoute.js

const PrivateRoute = ({ component: Component, ...rest }) => {
    const { user, isLoading } = useContext(AuthContext);

    if (isLoading) {
        return (
            <h1>Loading...</h1>
        );
    }

    return (
        <Route {...rest} render={(props) => (user ? <Component {...props} /> : <Redirect to='/login' />)} />
    );
};

AuthStore.js

This is where I manage my auth context.

const AuthStore = ({ children }) => {
    const [token, setToken] = useState();
    const [user, setUser] = useState();
    const [isLoading, setIsLoading] = useState(false);

    const setUserToken = async (userToken) => {
        localStorage.setItem('token', userToken);
        setToken(userToken);
        try {
            const decodedToken = jwtDecode(userToken);
            const currentUserData = await AuthService.getUserData(decodedToken.username);
            setUser(currentUserData);
        } catch (error) {
            console.log(error.name);
        }
    };

    useEffect(() => {
        setIsLoading(true);
        const localToken = localStorage.getItem('token');
        if (localToken) {
            setUserToken(localToken);
        }
        setIsLoading(false);
    }, []);

    return (
        <AuthContext.Provider value={{
            user, token, setUserToken, setUser, isLoading,
        }}
        >
            {children}
        </AuthContext.Provider>
    );
};

Thank you so much.

Source: Ask Javascript Questions

LEAVE A COMMENT