Kex
Kex

Reputation: 8589

useEffect is not always called with React Router

I have the following code for a "protected route" in React:

import React, { useState, useEffect, useContext } from 'react';
import LoadingPageContext from '../../contexts/LoadingPageContext';
import PropTypes from 'prop-types';
import { Redirect } from 'react-router-dom';
import authorizeWorker from '../../workers/authorize-worker';

/**
 * A protected route that calls the authorize API and redirects to login
 * on fail
 * @param {Element} component The component to redirect to on success
 * @param {String} path The route to redirect to after login
 */
const ProtectedRoute  = ({ component, path  }) => {
    const [isAuthenticated, setIsAuthenticated] = useState(null);
    const { loadingBarRef } = useContext(LoadingPageContext);
    const Component = component;
    console.log('Protected route rendered');

    useEffect(() => {
        console.log('protected route use effect')
        loadingBarRef.current.continuousStart();
        authorizeWorker()
            .then(() => setIsAuthenticated(true))
            .catch(() => setIsAuthenticated(false))
            .finally(() => loadingBarRef.current.complete());
    }, []);

    if (isAuthenticated === true) {
        return <Component />;
    }

    if (isAuthenticated === false) {
        return <Redirect 
                    to={{ pathname:'/login', state: { redirectPath: path }}} 
                />;
    }

    return null;
}

ProtectedRoute.propTypes = {
    component: PropTypes.func.isRequired,
    path: PropTypes.string
};

export default ProtectedRoute;

The router appears to be working ok and I see the correct pages/UI on the screen when I click on a new route. However useEffect does not seem to be called each time I route. I have confirmed this using console.log. The component does indeed render each time because Protected route rendered is printed to screen but protected route use effect isn't. Any idea what I am doing wrong here? For reference my router looks like this:

const DashboardSwitch = () => {
    const { path } = useRouteMatch();

    return (
        <Switch>
            <ProtectedRoute exact path={`${path}`} component={Home} />
            <ProtectedRoute exact path={`${path}/home`} component={Home} />
            <ProtectedRoute exact path={`${path}/bonus`} component={Bonuses} />
            <ProtectedRoute exact path={`${path}/newpage`} component={NewPage} />
            <ProtectedRoute exact path={`${path}/account`} component={Account} />

            <Route exact path={`${path}/mypages`} component={MyPages} />
            <Route path="*"><NotFound /></Route>
        </Switch>
    );
}

Amy help on this would be great. Thanks!

Upvotes: 0

Views: 782

Answers (1)

nir shabi
nir shabi

Reputation: 367

useEffect is the equivalent of componentDidMount and componentDidUpdate in class components. When you pass an empty array - [] - it will only act as componentDidMount - meaning only once. If you want the effect to be called each time a new route is presented, you should pass that as a prop:

useEffect(() => {
        console.log('protected route use effect')
        loadingBarRef.current.continuousStart();
        authorizeWorker()
            .then(() => setIsAuthenticated(true))
            .catch(() => setIsAuthenticated(false))
            .finally(() => loadingBarRef.current.complete());
    }, [path]);

Upvotes: 1

Related Questions