网站搜索

reactjs - React Router 自定义 props 数组无法加载,但自定义字符串可以


我有一个 ReactTS 应用,我通过 Router-Dom-Props 向另一个组件传递一个 prop。问题是我可以单独使用 meal.name,但如果我和 meal.food 一起使用它或者单独使用 meal.food,它就不再工作了。

Uncaught TypeError: meal.food is undefined

我检查了 TypeScript 和 useEffect 错误,但我还没有找到解决方案。

并且 props 在第一次渲染之前加载了吗?

更新 当我像这样使用时 location.state.meal.food 可以打印出 meal.food,但在我通过 useState 设置后就无法使用它——我在 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>
  );
};

从 .json 文件中的示例餐-对象

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

答案#1

问题

这里的问题似乎是,在初始渲染时,meal.food 未定义,因为 useEffect 钩子还没有将本地组件状态从路由状态(即 location.state)更新过来。

解决方案

在 React 中,将传递的数据和/或派生的“状态”存储在本地组件状态中被认为是一种反模式。直接使用传递的 location.state.meal 路由状态。你还应该使用防御性编程模式,以防用户从路由状态传递以外的任何地方导航到渲染 MealDetails 的路由。

示例:

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>
  );
};

答案#2

我认为这里不需要 useEffect。你可以直接从 location 对象中获取餐点。

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>
  );
};