My React project passes data from a component to FoodDetails
and this works, but I want it to navigate away if the state
property of location
from the useLocation
is null.
Code:
const FoodDetails = () => {
const navigate = useNavigate();
const location = useLocation();
if (location.state === null) {
navigate("/")
}
const food = location.state.food;
return (
<div className='FoodDetails'>
<div className="FoodDetailsName">{food.name}</div>
</div>
)
}
export default FoodDetails
It goes into the if
, but it ignores the navigate("/")
. I've placed a return after it and the return works so it just overlooks the navigate.
Why does it ignore it and how can I fix it?
CodePudding user response:
You need to place navigate("/")
inside useEffect
. Something like:
const FoodDetails = () => {
const navigate = useNavigate();
const location = useLocation();
const locationState = location.state;
useEffect(() => {
if(locationState === null){
navigate("/");
}
}, [locationState]);
const food = location.state.food;
return (
<div className='FoodDetails'>
<div className="FoodDetailsName">{food.name}</div>
</div>
);
}
export default FoodDetails;
useEffect
's callback will be run every time something inside its dependency array changes. In this case locationState
. Note that it's good idea to deconstruct dependencies before useEffect
.
CodePudding user response:
The navigate
function issues an imperative navigation action, and the current implementation is calling as an unintentional side-effect. While you could use a useEffect
hook to call navigate
as an intentional side-effect, the component still renders first and then the useEffect
hook callback is called. You'd see the returned JSX momentarily.
I would suggest conditionally rendering the Navigate
component instead. It will issue a declarative navigation action during the initial render cycle. The other food details JSX won't have a chance to be rendered.
In either case though the FoodDetails
component and route/page will be loaded/rendered. This is just a way to mitigate rendering momentary UI that you don't want a user to see.
Example:
import { Navigate } from 'react-router-dom';
const FoodDetails = () => {
const { state } = useLocation();
const { food } = state || {};
if (!food) {
return <Navigate to="/" />;
}
return (
<div className='FoodDetails'>
<div className="FoodDetailsName">{food.name}</div>
</div>
);
};
export default FoodDetails;