Home > Enterprise >  How can I navigate away if useLocation()-state is null without loading the page?
How can I navigate away if useLocation()-state is null without loading the page?

Time:01-18

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;
  • Related