【问题标题】:Why can't I use dot notation on React State?为什么我不能在 React State 上使用点符号?
【发布时间】:2021-02-10 23:59:10
【问题描述】:

我正在创建一个抽认卡应用程序,我目前正在尝试将抽认卡的正面设置为来自 API 的一些文本。

我的状态:

const [deckWithCards, setDeckWithCards] = useState([]);

deckWithCards 是一副抽认卡,它看起来像:

{name: 'Test Name', description: 'Test Description', id: 3, cards: Array(4)};

当我deckWithCards.cards 时,我得到:

[{id: 1, front: 'Front of card', back: 'Back of Card', deckId: 1}]

如果我在一副牌中有 4 张牌,我会得到一个数组,其中包含 4 个对象以及相应的数据。

我需要访问所有这些信息,但是,当我尝试执行 deckWithCards.cards.front 时,我得到“无法读取未定义的属性 'front'。”

我还尝试循环遍历卡片数组,例如:

let arr = [];
let allCards = deckWithCards.cards;
for (let i = 0; i < allCards.length; i++) {
   arr.push(allCards.front);
}

这给了我:“无法读取未定义的属性‘长度’。”

如何访问此卡片数组中的项目?

辅助函数:

export async function readDeck(deckId, signal) {
  const url = `${API_BASE_URL}/decks/${deckId}?_embed=cards`;
  return await fetchJson(url, { signal });
}

export async function listCards(deckId, signal) {
  const url = `${API_BASE_URL}/cards?deckId=${deckId}`;
  return await fetchJson(url, { signal });
}

我如何设置我的状态:

useEffect(() => {
    const abortController = new AbortController();

      readDeck(deckId, abortController.signal)
      .then(setDeckWithCards)
      .catch(setError)

      listCards(deckId, abortController.signal)
        .then(setCards)
        .catch(error)

      return () => abortController.abort();
  }, []);

【问题讨论】:

  • 使用deckWithCards.cards[0].front
  • 您得到的错误描述性很强。变量deckWithCards.cards 未定义。它可能只在开始时发生,但你应该研究它。试试console.log吧。
  • 看起来 deckWithCards.cards 已定义并且是一个数组,但 deckWithCards.cards[0].front 将是 ;)
  • @Dominik 当我控制台日志deckWithCards.cards[0] 时,它说:“无法读取未定义的属性'0'”
  • 您的问题将是因为它最初是一个空数组,并且您试图在数据填充到状态之前对其进行处理。在尝试对卡片数据进行处理或渲染之前,请检查 deckWithCards.cards 是否存在

标签: javascript reactjs react-hooks react-state


【解决方案1】:

在您设置卡片之前,您的useEffectfetch 仍在运行中有一段时间。在此期间,deckWithCards 的值将是您在useState 中提供的初始值。您的组件必须以可以正常运行并使用该初始值正确呈现的方式构建。如果已解决的牌组的最终值为object,那么您的初始值为空数组毫无意义。

const [deckWithCards, setDeckWithCards] = useState([]);

我建议您将初始状态设置为nullundefined。在访问 deckWithCards 上的任何属性之前,您必须检查它是否已设置为实际值。

const [deckWithCards, setDeckWithCards] = useState(null);
const allCards = deckWithCards ? deckWithCards.cards : [];

这里我们检查deckWithCards 是否为truthy(不是null)。如果我们有套牌,那么我们就可以从套牌中获取卡片。如果仍然是null,我们使用一个空数组。无论哪种方式,allCards 将始终是一个array,您可以使用map、循环等方式。

const fronts = allCards.map( card => card.front );
return (
  <ul>
    {allCards.map( (card) => (
       <div className="card" key={card.id}>
          {card.front}
       </div>
    ))}
  </ul>
)

【讨论】:

  • 就是这样!非常感谢。因为 API 调用后的延迟,我首先返回了一个空对象,这使得我的值未定义,然后卡片的对象会显示出来。有了这个条件,除非它实际初始化为对象值,否则它不会运行。真是一种解脱:)
【解决方案2】:

首先,第一个状态是[]

const [deckWithCards, setDeckWithCards] = useState([]);

所以在第一次运行时,我除了deckWithCards 是一个没有属性cards 的数组。这可能会触发您遇到的错误。

否则,如果deckWithCards 是一个对象数组,那么要访问第一个对象的卡片,您需要输入deckWithCards[0].cards

如果您使用上述对象正确设置 deckWithCards 的值,则 deckWithCards.cards 应该正确返回例外的卡片列表。

【讨论】:

  • 我尝试了两种方式。我不能做deckWithCards[0] 但我可以做deckWithCards.cards 来返回和4 个卡片对象的数组。但是尝试追加 [0].front 都行不通。
猜你喜欢
  • 2017-05-21
  • 2020-07-30
  • 2020-06-23
  • 2020-06-07
  • 1970-01-01
  • 2016-10-10
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多