Home > Back-end >  React Router Custom Props array doesnt load, but custom string does
React Router Custom Props array doesnt load, but custom string does

Time:12-12

I have a ReactTS-App and I pass a prop via Router-Dom-Props to another component. The problem here is that I can use meal.name alone, but if I use meal.food with it or meal.food alone it doesnt work anymore.

Uncaught TypeError: meal.food is undefined

I checked TypeScript- & useEffect-errors, but I didnt find a solution yet.

And are the props loaded before the first render?

UPDATE I can print the meal.food when I use it like that location.state.meal.food but I cannot use it from the useState after I set it - I console.log it in the useEffect.

Meal.tsx

  return (
    <Link className="Meal Link" to={`/MealDetails/${meal.id}`} state={{ meal: meal }}>
      <div className="MealIconMealName">
        <div className="MealName">{meal.name}</div>
      </div>
    </Link>
  );
};

MealDetails.tsx

const MealDetails = () => {
  const location = useLocation();
  const navigate = useNavigate();
  
  const [meal, setMeal] = useState(Object);

  useEffect(() => {
    if (location.state) {
      if (location.state.meal) {
        setMeal(location.state.meal);
        console.log("useEffect"   meal);
      }
    }
    return () => {};
  }, [location]);

  return (
    <div className="MealDetails">
      <header>
        <div className="HeaderText">{meal.name}</div>
      </header>
      <div className="MealDetailsCalorieCounter"></div>
      {meal.food.map((meal : any) => (
        <Food
          key={meal.id}
        />
      ))}
    </div>
  );
};

Example meal-Object out of the .json file

    { 
      "id": 1,
      "name": "Breakfast",
      "food": [
        {
            "name": "Waffeln",
            "kcal" : 505
        }
      ],
      "calories": 505
    }

CodePudding user response:

I don't think useEffect here is necessary. You can get the meal directly from the location object.

const MealDetails = () => {
  const location = useLocation();
  const { meal } = location.state;
  return (
    <div className="MealDetails">
      <header>
        <div className="HeaderText">{meal.name}</div>
      </header>
      <div className="MealDetailsCalorieCounter"></div>
      {meal.food.map((meal : any) => (
        <Food
          key={meal.id}
        />
      ))}
    </div>
  );
};

CodePudding user response:

Issue

The issue here is it seems that the meal.food is undefined on the initial render prior to the useEffect hook updating the local component state from the route state (i.e. from location.state).

Solution

It's considered a React anti-pattern to store passed data and/or derived "state" in local component state. Just consume the passed location.state.meal route state directly. You should also use defensive programming patterns in case a user navigates to the route rendering MealDetails from anywhere else other than the link that passes the route state.

Example:

const MealDetails = () => {
  const { state } = useLocation(); // <-- access state
  const navigate = useNavigate();
  
  const meal = state || {}; // <-- provide fallback value

  return (
    <div className="MealDetails">
      <header>
        <div className="HeaderText">{meal.name}</div>
      </header>
      <div className="MealDetailsCalorieCounter"></div>
      {(meal.food }} []).map((meal: any) => ( // <-- provide fallback array
        <Food key={meal.id} />
      ))}
    </div>
  );
};
  • Related