Reputation: 170
I've got a private route which redirects to an Auth component if there is nothing in local storage. At the moment it's not taking the storage into account as it takes me to the Auth page when there is local storage data and when there isn't. I am using redux in the application but not for this part yet, I wanted to get it working with a basic set up first.
I think may be my component hasn't had time to reload and register that there's a storage item. I can see it trying to navigate away but comes straight back to Auth. Can anyone help?
My private route:
export const ProtectedRoute = ({ component: Component, ...rest }: any) => {
const dispatch = useDispatch();
const [isAuthenticated, setIsAuthenticated] = useState<boolean>(false);
useEffect(() => {
const userData: any = localStorage.getItem('userData');
if (!userData) {
setIsAuthenticated(false);
}
setIsAuthenticated(true);
}, [dispatch])
return (
<Route {...rest} render={(props: any) =>
isAuthenticated ?
<Component {...props} />
: <Redirect to="/auth" />
} />
);
};
Component containing my routes:
export const Main = () => {
return (
<>
<MainContainer className="MainContainer">
<Switch location={location || background}>
<Route exact path="/">
<Home />
</Route>
<ProtectedRoute /*isAuthenticated={isAuthenticated}*/ component={Nativers} path="/nativers" exact />
</Switch>
</MainContainer>
</>
)
}
The auth component function handling any redirecting when you click on the login/sign up button:
const authHandler = async () => {
let action;
if (isSignUp) {
action = AuthActions.signup(
formState.inputValues.name,
formState.inputValues.email,
formState.inputValues.password,
formState.inputValues.repeatPassword
)
} else {
action = AuthActions.login(
formState.inputValues.email,
formState.inputValues.password
)
}
setError(null);
setIsLoading(true);
try {
await dispatch(action);
return <Redirect to="/nativers" />;
} catch (err) {
setError(err.message);
setIsLoading(false);
}
}
Upvotes: 0
Views: 1338
Reputation: 2573
When the page path is updated, the matching Route
component(s) is called to render whatever component was registered with it. The right place to put the logic to either redirect or not depending on the availability of localStorage
data should be inside the Route
component because that’s where it is guaranteed to be executed before render of the registered component.
However, in your code, this logic is placed outside the Route
component and even though you are trying to use dispatch
to update the value of isAuthenticated
variable, the update would only happen if the ProtectedRoute
component is re-rendered because of the way the useEffect
hook is setup.
There are multiple ways to fix this, but given what you already have, I think the easiest would be to do some thing like this:
export const ProtectedRoute = ({ component: Component, ...rest }: any) => {
return (
<Route {...rest} render={(props: any) =>
localStorage.getItem('userData') ?
<Component {...props} />
: <Redirect to="/auth" />
} />
);
};
Now, the logic to redirect or not lives inside the Route
component, consequently, whenever, there is page path matches that of the Route
component, the logic is executed and a redirect happens if needed.
Upvotes: 2