道具准备好之前的子组件渲染

Child component rendering before props are ready

我很确定我知道问题所在。我认为这是因为子组件在其道具准备好之前渲染。在看了很多教程和文档之后,我就是想不通我做错了什么。

我正在使用挂钩和 useEffect 在页面打开时从 firestore 获取数据。之后,我想将数据传递给子组件 "Table.js" 进行显示。 如果我在父组件中有 table 它工作正常,但是一旦我将 table 移动到它自己的组件我得到一个错误说 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;

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

非常感谢任何帮助。

你使用 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();
  }, []);