开发者问题收集

TypeError:无法读取未定义的 React js 的属性

2023-01-21
5178

我试图从每个页面输出一个数组中的数据。

此代码抛出错误 Uncaught TypeError: Cannot read properties of undefined (reading 'word')

虽然 array newArr 和数据 newArr[i].word 都输出到控制台。

const shuffle = (arr) => arr.sort(() => Math.random() - 0.5);

function Home({ data, num }) {
  const [newArr, setNewArr] = useState([]);
  const [i, setI] = useState(0);

  useEffect(() => {
    setNewArr(shuffle(data));
  }, []);

  const randomCard = () => {
    if (i < newArr.length - 1) {
      setI(i + 1);
      console.log(i);
      console.log(newArr);
      console.log(newArr[i].word);
    } else {
      setNewArr(shuffle(data));
      setI(0);
    }
  };
  return (
    <div>
      <div className="home-inner">
        {num >= 1 ? (
          <div className="home-stat">
            <div onClick={() => randomCard} className="home-random">
              <div className="hr-card">
                <p className="randomword">{newArr[i].word}</p>
                <p className="randomtranslate">{newArr[i].translate}</p>
              </div>
            </div>
          </div>
        ) : (
          <div>
            {" "}
              <Link className="main-btn" to="/addcard">
                Add 
              </Link>
          </div>
        )}
      </div>
    </div>
  );
}

export default Home;
1个回答

您的错误发生在组件的第一次渲染时。发生这种情况的原因是 i0newArr[] ,这是一个空数组,当您尝试渲染它时 - newArr[0] - 它返回 undefined

要解决此问题 - 使用实际值初始化 newArr 并在渲染位置添加额外检查。

function Home({ data, num }) {
  // Initialize newArr with initial data instead of useEffect
  const [newArr, setNewArr] = useState(shuffle([...data]));
  const [i, setI] = useState(0);

  // just a utility
  const randomCard = useMemo(() => {
    // you can add some console.logs here for debugging purposes, just in case
    if (!newArr || i < 0 || i >= newArr.length) return undefined;
    return newArr[i];
  }, [newArr, i]);

  // changed naming here
  const randomizeCard = () => {
    if (i < newArr.length - 1) {
      setI(i + 1);
    } else {
      setNewArr(shuffle([...data]));
      setI(0);
    }
  };

  return (
    <div>
      <div className="home-inner">
        {/* Added additinal check */}
        {num >= 1 && randomCard ? (
          <div className="home-stat">
            {/* fixed onClick binding */}
            <div onClick={randomizeCard} className="home-random">
              <div className="hr-card">
                <p className="randomword">{randomCard.word}</p>
                <p className="randomtranslate">{randomCard.translate}</p>
              </div>
            </div>
          </div>
        ) : (
          <div>
            {" "}
            <Link className="main-btn" to="/addcard">
              Add
            </Link>
          </div>
        )}
      </div>
    </div>
  );
}

注意:sort() 方法对数组元素进行就地排序并返回对同一数组的引用,因此您正在改变 data 参数,这通常不应该发生,同时如果您使用相同的“值”设置状态,React 将不会检测到更改,这意味着 Array 对象始终具有相同的引用。这里有一些详细信息: 将数组设置为等于另一个数组或使用三个点之间的区别 。 解决方案是 shuffle([...data]) ,它将创建 data 的浅表副本。

注意 2:在调用 setI(i + 1);console.log(i); 之后立即调用 - 不会按您预期的方式工作,因为 状态值将仅在下一次渲染时更新

Sergey Sosunov
2023-01-21