【问题标题】:React - TypeError: Cannot read property 'img' of undefinedReact - TypeError:无法读取未定义的属性“img”
【发布时间】:2021-09-24 02:29:22
【问题描述】:

我正在使用 React 制作纸牌游戏,由于某种原因,我收到了 TypeError: Cannot read property 'img' of undefined

导致错误的代码:

import React, { useState } from "react";

import Card from "./components/Card";

const App = () => {
    const [cards, setCards] = useState([
        {
            name: "King",
            img: "https://image.freepik.com/free-vector/king-crown-esport-logo-design_177315-269.jpg",
            pts: 10000,
        },
        {
            name: "Minister",
            img: "https://i.pinimg.com/474x/51/59/b3/5159b321713edef6c6a3b8f930f667a1.jpg",
            pts: 5000,
        },
        {
            name: "Cop",
            img: "https://image.shutterstock.com/image-vector/police-officer-badge-icon-vector-260nw-613493573.jpg",
            pts: 100,
        },
        {
            name: "Thief",
            img: "https://images1.livehindustan.com/uploadimage/library/2019/05/03/16_9/16_9_1/thief_symbolic_photo__1556892712.jpg",
            pts: 0,
        },
    ]);

    const [shuffledCards, setShuffledCards] = useState([]);

    for (let i = 0; i < 4; i++) {
        const randCard = cards[Math.floor(Math.random() * (cards.length + 1))];
        setShuffledCards([...shuffledCards, randCard]);
        setCards(cards.filter((c) => c !== randCard));
    }

    return (
        <div style={{ display: "flex", flexDirection: "row" }}>\
            {shuffledCards.map((c) => (
                <Card img={c.img} name={c.name} pts={c.pts} />
            ))}
        </div>
    );
};

export default App;

项目链接(在线 Gitpod.io)-https://purple-salmon-uy3kza3n.ws-us10.gitpod.io/?folder=vscode-remote%3A%2F%2Fsapphire-quokka-1i5clgk7.ws-us09.gitpod.io%3A443%2Fworkspace(注意它可能会改变,一些奇怪的 gitpod 事情)

现在,当我在 for 循环中打印 shuffledCards 数组时,经过一些循环后,我注意到一个未定义的对象被添加到数组中。我认为这是问题所在,我不知道为什么或如何发生,以及如何解决它。

期待您的来信。提前谢谢你。

【问题讨论】:

  • 您希望什么时候洗牌?当前,您正在尝试在每次组件呈现时执行此操作。在 state 中存储 2 个数组有点多余,只需存储一个并在生命周期挂钩中对其进行 shuffle。
  • @DrewReese 你认为这会修复错误吗?
  • @DrewReese 我是 React 和 JavaScirpt 的新手,你能告诉我该怎么做吗?

标签: reactjs react-hooks undefined typeerror


【解决方案1】:

主要问题是你如何计算随机卡片,你是从数组中索引出来的。

const randCard = cards[Math.floor(Math.random() * (cards.length + 1))];

你想使用长度。

const randCard = cards[Math.floor(Math.random() * (cards.length))];

另一个问题是你无条件地从组件的主体更新状态,这将导致渲染循环。

将循环放在useEffect 钩子中并使用功能状态更新,因为您将状态更新排入循环中。

useEffect(() => {
  for (let i = 0; i < 4; i++) {
    const randCard = cards[Math.floor(Math.random() * (cards.length))];
    setShuffledCards((shuffledCards) => [...shuffledCards, randCard]);
    setCards((cards) => cards.filter((c) => c !== randCard));
  }
}, []);

存储两个数组是多余的。我会研究并实施fisher-yates shuffle。

这是一个示例效果:

useEffect(() => {
  setCards((cards) => {
    // create copy
    const shuffledCards = cards.slice();

    // shuffle
    for (let i = cards.length - 1; i >= 0; i--) {
      const randIndex = Math.floor(Math.random() * i);
      [shuffledCards[i], shuffledCards[randIndex]] = [
        shuffledCards[randIndex],
        shuffledCards[i]
      ];
    }

    // return next state
    return shuffledCards;
  });
}, [shuffledCards]);

演示

在这个演示中,我添加了一个随机播放按钮,这会更新 useEffect 依赖项以触发另一个随机播放。这种效果依赖可以是您需要触发的任何东西,但对于您的特定用例。

演示代码

const App = () => {
  const [cards, setCards] = useState([
    {
      name: "King",
      img:
        "https://image.freepik.com/free-vector/king-crown-esport-logo-design_177315-269.jpg",
      pts: 10000
    },
    {
      name: "Minister",
      img:
        "https://i.pinimg.com/474x/51/59/b3/5159b321713edef6c6a3b8f930f667a1.jpg",
      pts: 5000
    },
    {
      name: "Cop",
      img:
        "https://image.shutterstock.com/image-vector/police-officer-badge-icon-vector-260nw-613493573.jpg",
      pts: 100
    },
    {
      name: "Thief",
      img:
        "https://images1.livehindustan.com/uploadimage/library/2019/05/03/16_9/16_9_1/thief_symbolic_photo__1556892712.jpg",
      pts: 0
    }
  ]);

  const [shuffledCards, setShuffledCards] = useState(true);
  const shuffle = () => setShuffledCards((t) => !t);

  useEffect(() => {
    setCards((cards) => {
      const shuffledCards = cards.slice();

      for (let i = cards.length - 1; i >= 0; i--) {
        const randIndex = Math.floor(Math.random() * i);
        [shuffledCards[i], shuffledCards[randIndex]] = [
          shuffledCards[randIndex],
          shuffledCards[i]
        ];
      }
      return shuffledCards;
    });
  }, [shuffledCards]);

  return (
    <>
      <div style={{ display: "flex", flexDirection: "row" }}>
        {cards.map((c) => (
          <Card key={c.name} img={c.img} name={c.name} pts={c.pts} />
        ))}
      </div>
      <button type="button" onClick={shuffle}>
        Shuffle Cards
      </button>
    </>
  );
};

【讨论】:

  • 实际上@Drew Reese,因为使用了Math.floor,所以正常的数组长度应该可以正常工作。 const randCard = cards[Math.floor(Math.random() * (cards.length)];
  • @DrewReese,我试过useEffect,还是报错,会试试你的初步建议
  • @SakisTsalk,你确定吗?
  • 是的,检查Math.Random()
  • @DrewReese 非常感谢,它现在正在工作
猜你喜欢
  • 2023-04-01
  • 2020-07-10
  • 2019-07-07
  • 2021-03-10
  • 2020-02-10
  • 2021-04-17
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多