开发者问题收集

在 props 准备好之前渲染子组件

2019-12-03
818

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

我在页面打开时使用 hooks 和 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;

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

我非常感谢任何帮助。

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();
  }, []);
Andres
2019-12-03