为啥我的 JSON 响应在 forEach 上崩溃? TypeError 未定义

Posted

技术标签:

【中文标题】为啥我的 JSON 响应在 forEach 上崩溃? TypeError 未定义【英文标题】: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 前缀。 【参考方案1】:

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

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

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

要解决这个问题,您可以

做一个非身份equality comparison:state.submissions != null,或者 只需通过 state.submissions &amp;&amp; ( ... ) 测试truthiness

除了 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);

以上是关于为啥我的 JSON 响应在 forEach 上崩溃? TypeError 未定义的主要内容,如果未能解决你的问题,请参考以下文章