When a user arrives in this component. I want to execute two function in the useEffect hook: - hasError (returns true if there is an error) - hasState (returns true if there is an state)
Based on the state i want to return a specific component. If access is false than If it is true than
The first time the user comes on the page it says that access if false
when i refresh the page it is true
Why doesn't the state update the first time?
Am I using the wrong lifecycle method?
Component:
const ContinueRouteComponent = () => {
const dispatch = useDispatch();
// const [access, setAccess] = useState(false);
// const [error, setError] = useState(false);
const query = useQuery();
//check if user has valid state
const hasState = (stateId: string) => {
// No state is given in the uri so no access
if(stateId === null) {
return false;
}
// You have a state in the uri but doesn't match the localstorage
return localStorage.getItem(stateId) !== null;
};
const hasError = (error: string) => {
return error !== null;
};
const [access, setAccess] = useState(() => hasState(query.get("state")));
const [error, setError] = useState(() => hasError(query.get("error")));
useEffect(() => {
dispatch(fetchResources());
},[]);
if(error){
let errorType = query.get("error");
let errorDescription = query.get("error_description");
return <Redirect exact={true} to={{
pathname: '/error',
state: {
error: errorType,
description: errorDescription
}
}} />;
}
if(access){
const retrievedStorage = JSON.parse(localStorage.getItem(query.get("state")));
localStorage.removeItem(query.get("state"));
return <Redirect exact to={retrievedStorage} />
} else {
return <Redirect to="/"/>
}
};
export default ContinueRouteComponent
You set the default state as false, this will be its value on the first render. Then when you trigger the effect setAccess(hasState(someValue));
it sets up access to be true on the next render.
The change in state triggers a rerender with the new value but does not interrupt the current rendering.
You might spend more time thinking about yoursetup like, why not initialise the state with values?
const [access, setAccess] = useState(() => hasState(someValue));
const [error, setError] = useState(() => hasError(someValue));