开发者问题收集

TypeError:即使 useState() 已使用数组初始化,也无法读取未定义的属性(读取“map”)

2022-03-04
27804

我得到了“TypeError:无法读取未定义的属性(读取‘map’)”, 即使 useState() 是用数组初始化的 。该错误只发生在一个组件中。我认为其他组件也以相同的方式使用 useState 和 useEffect,因此不会出现此错误。

import { useState, useEffect } from "react/cjs/react.development";
import * as constants from "../../../../constants";

export default function Keywords(props) {
  const [movieKeywords, setMovieKeywords] = useState([]);

  useEffect(() => {
    const fetchKeywords = async () => {
      const data = await fetch(
        `${constants.TMDB_BASE_PATH}movie/${props.id}/keywords?api_key=${constants.API_KEY}`
      );

      const jsonData = await data.json();
      setMovieKeywords(jsonData.keywords);
      console.log("xdd");
    };

    fetchKeywords();
  }, []);
  return (
    <div className="flex flex-wrap">
      {movieKeywords.map((keyword) => {
        return (
          <div className="border font-oxygen m-1 rounded-xl cursor-pointer text-xs text-gray-300 px-2 py-1">
            <p>{keyword.name}</p>
          </div>
        );
      })}
    </div>
  );
}

如果有人能给我指明正确的方向,我将非常高兴。

2个回答

API 调用和渲染的时间可能只差几毫秒。一个好的做法是在尝试渲染任何 JSX 之前检查要映射的数组是否存在。将初始状态设置为 null,然后在映射行上执行 可选链接

像这样重构您的组件:

import { useState, useEffect } from "react/cjs/react.development";
import * as constants from "../../../../constants";

export default function Keywords(props) {
  const [movieKeywords, setMovieKeywords] = useState();

  useEffect(() => {
    const fetchKeywords = async () => {
      const data = await fetch(
        `${constants.TMDB_BASE_PATH}movie/${props.id}/keywords?api_key=${constants.API_KEY}`
      );

      const jsonData = await data.json();
      setMovieKeywords(jsonData.keywords);
      console.log("xdd");
    };

    fetchKeywords();
  }, []);
  return (
    <div className="flex flex-wrap">
      {movieKeywords?.map((keyword) => {
        return (
          <div className="border font-oxygen m-1 rounded-xl cursor-pointer text-xs text-gray-300 px-2 py-1">
            <p>{keyword.name}</p>
          </div>
        );
      })}
    </div>
  );
}

注意 movieKeywords?.map ,这不会执行映射,直到 movieKeywords 不为 null,这意味着它将等到提取解析并设置您的状态。

PsiKai
2022-03-04

“jsonData.keywords 并非未定义。” - 但该错误实际上是在通知您它已未定义。 setMovieKeywords(jsonData.keywords); 更新状态,然后 movieKeywords 未定义,并且无法访问 .map 属性/方法。

据我所知,您缺少 props.id 作为 useEffectfetch 的依赖项。听起来 props.id 最初不是 API 请求的有效值,并且您收到未定义的 keywords 响应。

只有在您拥有所有必需参数的情况下才应发出 API 请求,并且您的代码应该足够强大,能够处理潜在的无效和不良响应。

  1. props.id 添加到 useEffect 钩子的依赖项数组。
  2. 仅当 id 为真时才发出 fetch 请求。
  3. 处理可能被拒绝的 fetch 中的 Promises。
  4. 处理任何具有未定义值的潜在不良状态更新。

示例:

import { useState, useEffect } from "react/cjs/react.development";
import * as constants from "../../../../constants";

export default function Keywords({ id }) {
  const [movieKeywords, setMovieKeywords] = useState([]);

  useEffect(() => {
    const fetchKeywords = async (id) => {
      try { // <-- (3) use try/catch to handle rejected Promise or other exceptions
        const data = await fetch(
          `${constants.TMDB_BASE_PATH}movie/${id}/keywords?api_key=${constants.API_KEY}`
        );

        const jsonData = await data.json();

        if (jsonData) { // <-- (4) only update state if defined response value
          setMovieKeywords(jsonData.keywords);
        }
      } catch(error) {
        // handle any errors, log, set error state, ignore(?), etc...
      }

      console.log("xdd");
    };

    if (id) { // <-- (2) only fetch if `id` is truthy
      fetchKeywords(id);
    }
  }, [id]); // <-- (1) add `id` as dependency

  return (
    <div className="flex flex-wrap">
      {movieKeywords?.map((keyword) => { // <-- Use Optional Chaining in case `movieKeywords` becomes falsey for any reason
        return (
          <div className="border font-oxygen m-1 rounded-xl cursor-pointer text-xs text-gray-300 px-2 py-1">
            <p>{keyword.name}</p>
          </div>
        );
      })}
    </div>
  );
}
Drew Reese
2022-03-04