为什么我的 JSON 响应在 forEach 上崩溃?未定义类型错误

Why does my JSON response crash on forEach? With TypeError undefined

我设置了一个 Cloud Firebase 数据库并向它发出了获取请求,但是当我尝试遍历 returned 对象中的数组时,我得到 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;

如果我return以下而不是迭代数组:

 <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 将是 undefined,而 undefined !== nulltrue,因为它们不是 strictly equal

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

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

要解决这个问题,您可以


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

所以你的数据,它有一个提交 属性,在你的组件状态自己的提交下 属性。

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

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

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


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

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

如果您的环境支持(或 polyfill)optional chaining you can simplify this even further by eliminating the conditional altogether, and while we're at it use the arrow function's implicit return:

state.submissions?.map?.((element) => <p>{element.patientName}</p>)
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 does not have forEach.

来处理这种情况