【问题标题】:Why does my JSON response crash on forEach? With TypeError undefined为什么我的 JSON 响应在 forEach 上崩溃? TypeError 未定义
【发布时间】:2021-08-16 09:44:03
【问题描述】:

我设置了一个 Cloud Firebase 数据库,我正在向它发出 fetch 请求,但是当我尝试遍历返回对象中的数组时,我得到 TypeError: Cannot read property 'forEach' of undefined,但我不确定为什么......我看到了一些帖子建议 JSON.parse res 但它没有改变输出..

import React, { useState, useEffect } from "react";
import axios from "axios";

const Submissions = () => {
    const [state, setState] = useState({});

    useEffect(() => {
        axios
            .get("/submissions")
            .then((res) => {
                setState({
                    submissions: res.data,
                });
            })
            .catch((err) => {
                console.error(err);
            });

        // eslint-disable-next-line
    }, []);

    return (
        <div style={{ paddingTop: "3rem" }}>
            <h1>Submissions</h1>

            {state.submissions !== null &&
                state.submissions.forEach((element) => {
                    <p>{element.patientName}</p>;
                })}
        </div>
    );
};

export default Submissions;

如果我返回以下内容而不是迭代数组:

 <p>{JSON.stringify(state)}</p>

但我确实得到了我期望的虚拟数据响应:

{"submissions":[{"submissionId":"NxkofnOyiZSjpBa918it","patientName":"Bobby Hill","onsetDate":"2021-05-28T01:41:44.368Z","immuno":true,"highrisk":false,"symptoms":true,"collectionDate":"2021-05-28T01:41:44.368Z","createdAt":"2021-05-28T01:42:00.042Z"},{"submissionId":"PuyDsvIlNC5Mi1h5u7b5","patientName":"Theo","onsetDate":"2021-05-28T01:20:06.275Z","immuno":false,"highrisk":false,"symptoms":false,"collectionDate":"2021-05-28T01:20:06.275Z","createdAt":"2021-05-28T01:20:06.275Z"}]}

【问题讨论】:

  • 你可以去掉 state.submissions!==null 并用 state.submissions?.map 替换 state.submissions.forEach。其中? 称为optional chaining 运算符。 .forEach 不返回数组,但您需要这样做,这就是我们使用 .map 的原因。还要在 &lt;p&gt;{element.patientName}&lt;/p&gt; 之前添加 return 前缀。

标签: json reactjs google-cloud-firestore axios typeerror


【解决方案1】:

最初state.submissions 将是undefined,而undefined !== nulltrue,因为它们不是strictly equal

state.submissions !== null => undefined !== null => true

因为即使没有数据,state.submissions !== null 的计算结果仍为 true,因此您最终尝试在 undefined 上调用 forEach

要解决这个问题,您可以


除了 API 响应中的属性之外,您还将状态设置为具有自己的提交属性的对象。

因此,具有 submits 属性的数据位于组件状态自己的 submits 属性下。

有效:setState( { submissions: { submissions: […] }}

因此,您必须访问 state.submissions.submissions 才能访问数组。

改为直接设置响应:setState(res.data)


您将遇到的下一个问题是您的 forEach 中的任何内容都不会呈现,因为该函数不会返回任何内容。将其更改为 map 并在每次迭代时返回标记:

{state.submissions &&
  state.submissions.map((element) => {
    return <p>{element.patientName}</p>;
  })
}

如果您的环境支持(或 polyfills)optional chaining,您可以通过完全消除条件来进一步简化此操作,而我们使用箭头函数的 implicit return

state.submissions?.map?.((element) => <p>{element.patientName}</p>)

【讨论】:

  • 我尝试使用 state.submissions && 来测试真实性,但也让我感到困惑
  • 您还将状态设置为具有独立于 API 响应的自己的 submissions 属性的对象,因此具有提交属性的数据位于您所在状态的提交属性下。有效:setState( { submissions: { submissions: […] }}. So you’d have to access state.submissions.submissions to get to the array. Set the response directly instead: setState(res.data)` 答案已更新。
  • 我尝试使用带返回的地图,它终于奏效了! ``` {state.submissions && state.submissions.map((element, i) => { console.log(element); return ; })} ```
【解决方案2】:
import React, { useState, useEffect } from "react";
import axios from "axios";

const Submissions = () => {
    const [submissions, setSubmissions] = useState([]);

    useEffect(() => {
        axios
            .get("/submissions")
            .then((res) => {
                setSubmissions(res.data);
            })
            .catch((err) => {
                console.error(err);
            });

        // eslint-disable-next-line
    }, []);

    return (
        <div style={{ paddingTop: "3rem" }}>
            <h1>Submissions</h1>

            {submissions.length &&
                submissions.forEach((element) => {
                    <p>{element.patientName}</p>;
                })}
        </div>
    );
};

编辑:我推荐上面的代码。我假设您在数据之间分离状态并对此给出了答案。以下答案不适用于您的情况。不管怎样,我拿着它以防有人需要它。

问题是你的渲染部分是在useEffect之前执行的。所以在第一次渲染中,你的状态是{}。您必须通过将状态设置为 [] 而不是 {}.Object 来处理这种情况。Object 没有 forEach

【讨论】:

  • setSubmissions(res.data) 将状态设置为具有提交属性的对象。如果你想走这条路,你想把它改成setSubmissions(res.data.submissions);
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2016-07-14
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多