为啥我的 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 未定义的主要内容,如果未能解决你的问题,请参考以下文章

为啥我的程序在管理这个 JSON 文件时会崩溃?

为啥我的 foreach 循环与 users.json 文件中的键不匹配

仍然使用同源策略 为啥 JSON 响应在 https 链接上使用 jquery ajax 是空白的?

我想使用数组列出 JSON 字符串中的数据,但为啥我的应用程序崩溃了?

为啥我的 json 响应对象返回 nil?

为啥在解构响应对象后会引发“无法在 'Response' 上执行 'json'”错误