【问题标题】:Child component rendering before props are ready在 props 准备好之前渲染子组件
【发布时间】:2020-03-28 11:59:59
【问题描述】:

我很确定我知道问题所在。我认为这是因为子组件在其道具准备好之前渲染。在查看了许多教程和文档后,我无法弄清楚我做错了什么。

当页面打开时,我正在使用钩子和 useEffect 从 Firestore 获取数据。之后,我想将数据传递给要显示的子组件“Table.js”。 如果我在父组件中有表格,它可以正常工作,但是一旦我将表格移动到它自己的组件中,我就会收到一条错误消息,说 forms.map 不是函数`TypeError:forms.map 不是函数

这是我的父组件代码 MainScreen.js

`

  function MainScreen() {
  const [forms, setForms] = useState([]);
  let history = useHistory();

  useEffect(() => {
    const fetchData = async () => {
      const unsubscribe = await firebase
        .firestore()
        .collection("")
        .doc("")
        .collection("")
        .onSnapshot(snapshot => {
          const newForms = snapshot.docs.map(doc => ({
            id: doc.id,
            ...doc.data()
          }));

          setForms(newForms);
        });
      return () => unsubscribe();
    };
    fetchData();
  }, []);



  const openSignFormPage = () => {
    history.push("/");
  };

  console.log("MainScreen forms:", forms);

  return (
    <div
      style={{
        display: "flex",
        flexDirection: "column",
        margin: "auto",
        padding: "2% 4%"
      }}>
      {!forms.length ? <div>Loading</div> : <MyTable forms={forms} />}

      <div
        style={{
          border: "solid red 1px",
          display: "flex",
          flexDirection: "row",
          justifyContent: "space-around"
        }}>
        <Button color={"blue"} onClick={openSignFormPage}>
          Sign forms
        </Button>
        <Button color={"blue"}>Create / Edit forms</Button>
      </div>
    </div>
  );
}
export default MainScreen;

Table.js的代码

import React, { useEffect, useState } from "react";
import Table from "@material-ui/core/Table";
import TableHead from "@material-ui/core/TableHead";
import TableRow from "@material-ui/core/TableRow";
import TableCell from "@material-ui/core/TableCell";
import TableBody from "@material-ui/core/TableBody";
import Paper from "@material-ui/core/Paper";
import { makeStyles } from "@material-ui/core/styles";
import { useHistory } from "react-router-dom";

const useStyles = makeStyles({
  root: {
    width: "100%",
    overflowX: "auto"
  },
  table: {
    minWidth: 650
  }
});

const MyTable = forms => {
  let history = useHistory();

  const classes = useStyles();
  //const forms = useForms("yVhc97ImwzFRz6Kh7Mbn");
  console.log("Table Page forms: ", forms);

  const openViewDisclaimerPage = row => {
    history.push("/viewform", { ...row });
  };

  return (
    <Paper className={classes.root}>
      <Table className={classes.table} aria-label="simple table">
        <TableHead>
          <TableRow>
            <TableCell>Child Name</TableCell>
            <TableCell>Time in</TableCell>
            <TableCell>Time out</TableCell>
            <TableCell>Parent Name</TableCell>
            <TableCell>shoe Box Number</TableCell>
          </TableRow>
        </TableHead>
        <TableBody>
          {forms.map(row => (
            <TableRow
              hover
              onClick={() => openViewDisclaimerPage(row)}
              key={row.id}>
              <TableCell component={"th"} scope={"row"}>
                {row.children &&
                  row.children.length &&
                  row.children[0].childName}
              </TableCell>
              <TableCell>{row.timeIn}</TableCell>
              <TableCell>{row.timeOut}</TableCell>
              <TableCell>{row.parentName}</TableCell>
              <TableCell>{row.shoeBoxNumber}</TableCell>
            </TableRow>
          ))}
        </TableBody>
      </Table>
    </Paper>
  );
};

export default MyTable;

稍微更改代码以尝试不同的方法时,它会渲染加载,然后数据准备就绪,但不会重新渲染,而是停留在加载屏幕上。

非常感谢任何帮助。

【问题讨论】:

  • const MyTable = ({forms}) =&gt;你拿到了这里的道具,需要解构。
  • 如前所述,从 props 中销毁表单,然后条件渲染 forms? forms.map(...):&lt;div&gt;No form data!&lt;/div&gt;
  • @colburton 是的,成功了!谢谢:) 我想这是我对反应缺乏了解。我正要指出一个更新,它正在显示加载屏幕,然后按应有的方式渲染子组件,但后来它说 forms.map 不是一个函数,所以在这一点上,我知道它不再是数据加载问题。谢谢,我可以用什么来发现这是问题所在?
  • @colburton 你想添加你的评论,作为一个答案,所以我可以接受它。干杯

标签: javascript reactjs async-await react-hooks use-effect


【解决方案1】:

你使用 props 的语法有误:

const MyTable = forms => {
  ...
}

应该是:

const MyTable = ({ forms }) => {

您也没有从 useEffect() 回调中返回取消订阅。应该是:

useEffect(() => {
  ...
  return fetchData();
}, []);

或者您甚至可以删除 fetchData() 并改用它的正文:

useEffect(() => {
   const unsubscribe = await firebase
        .firestore()
        .collection("")
        .doc("")
        .collection("")
        .onSnapshot(snapshot => {
          const newForms = snapshot.docs.map(doc => ({
            id: doc.id,
            ...doc.data()
          }));

          setForms(newForms);
        });
      return () => unsubscribe();
  }, []);

【讨论】:

  • 感谢您的回答,正如@colburton 在上面的评论中所说,我需要 const MyTable = ({forms}) => 来解构,这对我有用。我刚刚对你答案的第二部分有疑问。在调用等待之前,您不需要在函数中进行异步吗?我试过你 useEffect 代码,但得到一个错误,说等待,必须在异步函数中,我知道它必须这样做。
  • 你是对的,我想念你在那里等待。我的回答是强调您可能在退订时遇到问题,因为您没有为 useEffect() 回调返回此函数
猜你喜欢
  • 1970-01-01
  • 2018-07-23
  • 1970-01-01
  • 2021-07-25
  • 1970-01-01
  • 1970-01-01
  • 2020-08-07
  • 2021-05-18
  • 2021-01-06
相关资源
最近更新 更多