首页 > 解决方案 > TypeError:即使尚未调用组件,也无法读取未定义的属性“映射”

问题描述

我当前正在构建的应用程序中的一个页面是“类别”页面。它呈现来自特定类别的行表。这些行也有评论。

上校 x col y 注释
第 1 行 x 第 1 行 看法
第 2 行 x 第 1 行 看法

我正在使用react redux,当我转到“类别”页面时,尚未向状态添加评论,仅添加了类别的相关行(他们的评论在我数据库中的不同表中。我是尝试制作一个组件(“查看”按钮),该组件将打开一个对话框,在该对话框中获取并显示所选行的注释。

问题是,一旦我进入类别页面,我的标题中就会出现错误(指向我在下面加星标的地图功能的错误)

class MyComments extends Component {
  state = {
    open: false,
    oldPath: "",
    newPath: "",
  };

  handleOpen = () => {
    let oldPath = window.location.pathname;

    const { categoryId, rowId } = this.props;
    const newPath = `/categories/${categoryId}/row/${rowId}`;

    if (oldPath === newPath) oldPath = `/categories/${categoryId}`;

    window.history.pushState(null, null, newPath);

    this.setState({ open: true, oldPath, newPath });
    this.props.getRow(this.props.rowId);
  };
  handleClose = () => {
    window.history.pushState(null, null, this.state.oldPath);
    this.setState({ open: false });
    this.props.clearErrors();
  };
  render() {
    const {
      row: { comments },
      UI: { loading },
    } = this.props;
    const commentsDialog = loading ? (
      <div>
        <CircularProgress size={200} thickness={2} />
      </div>
    ) : (
      <List>************
        {comments.map((comment) => (
          <ListItem>{comment.body}</ListItem>
        ))}
      </List>***********
    );
    return (
      <Fragment>
        <Button onClick={this.handleOpen}>
          <UnfoldMore color="primary" />
        </Button>
        <Dialog
          open={this.state.open}
          onClose={this.handleClose}
          fullWidth
          maxWidth="sm"
        >
          <Button onClick={this.handleClose}>
            <CloseIcon />
          </Button>
          <DialogContent>{commentsDialog}</DialogContent>
        </Dialog>
      </Fragment>
    );
  }
}

MyComments.propTypes = {
  clearErrors: PropTypes.func.isRequired,
  getRow: PropTypes.func.isRequired,
  rowId: PropTypes.string.isRequired,
  row: PropTypes.object.isRequired,
  UI: PropTypes.object.isRequired,
};

const mapStateToProps = (state) => ({
  row: state.data.row,
  UI: state.UI,
});

const mapActionsToProps = {
  getRow,
  clearErrors,
};

export default connect(mapStateToProps, mapActionsToProps)(MyComments);

您可能会注意到的一件事是,当对话框打开时我推送到一个新的 url。我为调试所做的一件事是我注释掉了上面的comments.map(被*包围),然后我能够毫无错误地单击对话框并转到新的url。一旦在 url 上,我将代码改回 comments.map,它们显示在对话框的列表中。所以我的问题是,我的应用程序试图在将这些选项添加到我的状态之前呈现这些选项。我想我想知道为什么我的应用在对话框打开之前就关心这个地图功能?

我的'getRow'函数返回一个json,如下所示,所以这不是问题,我已经控制台记录了它以确保数据被正确获取,在这和我上面所说的之间,我不认为我的动作或减速器是问题,所以我没有添加它们,但让我知道它们是否相关。

{
    "categoryId": "id",
    "index": "2",
    "body": "New test",
    "disapproveCount": 0,
    "approveCount": -1,
    "createdAt": "2021-03-05T23:16:26.142Z",
    "rowId": "id",
    "comments": [
        {
            "index": 2,
            "body": "hello",
            "rowId": "id"
        }
    ]
}

我已经遇到这个问题大约一个星期了,但是我先完成了其他所有事情,因为我无法弄清楚,并且还认为在 stackoverflow 上解释起来太难了。我希望这有某种意义,仍然不知道我是否正确/完整地解释它,所以我会非常感激/对任何建议感到惊讶。

另外,理想情况下,我只想不在对话框中显示这些评论,因此无需按下按钮即可查看它们,但在尝试对话框之前我遇到了这个问题,我想加载一个对话框并在一个新的url 将解决问题,即在我打开这个新页面/url 之前不会尝试呈现选项

这可能是相关的:

类别页面(称为文档)

class document extends Component {
  componentDidMount() {
    const categoryId = this.props.match.params.categoryId;
    this.props.getCategory(categoryId);
  }

  render() {
    const categoryId = this.props.match.params.categoryId;

    const { category, loading } = this.props.data;
    let placeholder = !loading ? (
      <div>
        <center>
          <h1>{categoryId}</h1>
          <h1> </h1>
        </center>

        <br></br>
        <Paper>
          <TableContainer>
            <TableHead>
              (...)
            </TableHead>
            <TableBody>
              {category.map((row) => (
                <TableRow key={row.rowId}>
                   (...)
                  <TableCell align="left">
                    <MyComments rowId={row.rowId} categoryId={categoryId} />
                  </TableCell>
                       (...)
              </TableRow>
              ))}
            </TableBody>
          </TableContainer>
        </Paper>
        <br></br>
        <MyForm categoryId={categoryId} />
      </div>
    ) : (
      <p>Loading...</p>
    );
    return <div>{placeholder}</div>;
  }
}

document.propTypes = {
  getCategory: PropTypes.func.isRequired,
  data: PropTypes.object.isRequired,
};

const mapStateToProps = (state) => ({
  data: state.data,
});

export default connect(mapStateToProps, { getCategory })(document);

我不确定这是否是确切的问题,但我认为 Tl;Dr 是:为什么我的对话框中的 map 函数在尚未调用时关心未定义的内容?非常感谢任何帮助!

标签: reactjsreact-redux

解决方案


放置一个?对象键后的符号。它将检查对象键的值是否未定义或为空,然后再继续。


  <List>
    {comments?.map((comment) => (
      <ListItem>{comment.body}</ListItem>
    ))}
  </List>


推荐阅读