【问题标题】:validateDOMNesting(...): <tr> cannot appear as a child of <div> problemvalidateDOMNesting(...): <tr> 不能作为 <div> 问题的子项出现
【发布时间】:2021-08-23 18:59:30
【问题描述】:

我在我的react.js 项目中使用material-ui。当我尝试测试我的Row 组件时,我得到了console.error

  Warning: validateDOMNesting(...): <tr> cannot appear as a child of <div>.

这是我的Row 组件:

const Row: React.FC<RowProps> = ({ course }) => {
  const [open, setOpen] = useState(false);
  const classes = useRowStyles();

  const isDesktopOrLaptop = useMediaQuery({
    query: '(min-device-width: 992px)',
  });

  const boxMargin = isDesktopOrLaptop ? 8 : 1;

  return (
    <>
      <TableRow className={classes.root}>
        <TableCell>
          <IconButton
            aria-label="expand row"
            size="small"
            onClick={() => setOpen(!open)}>
            {open ? (
              <KeyboardArrowUpIcon fontSize="large" />
            ) : (
              <KeyboardArrowDownIcon fontSize="large" />
            )}
          </IconButton>
        </TableCell>
        <TableCell component="th" scope="row">
          <Typography variant="h5" component="h5">
            {course.course}
          </Typography>
        </TableCell>
        <TableCell align="right">
          <Typography variant="h5" component="h5">
            {course.openedLessonsCount}
          </Typography>
        </TableCell>
      </TableRow>
      <TableRow>
        <TableCell style={{ paddingBottom: 0, paddingTop: 0 }} colSpan={6}>
          <Collapse in={open} timeout="auto" unmountOnExit>
            <Box marginX={boxMargin} marginY={1}>
              <Typography variant="h5" gutterBottom component="h5">
                Projects
              </Typography>
              <Table size="small" aria-label="purchases">
                <TableHead>
                  <TableRow>
                    <TableCell>
                      <Typography variant="h6" gutterBottom component="h6">
                        Name
                      </Typography>
                    </TableCell>
                    <TableCell align="right">
                      <Typography variant="h6" gutterBottom component="h6">
                        Completed Lessons
                      </Typography>
                    </TableCell>
                  </TableRow>
                </TableHead>
                <TableBody>
                  {course.projects &&
                    course.projects.map((project: IProject) => (
                      <TableRow key={project.project}>
                        <TableCell component="th" scope="row">
                          <Typography variant="body1" gutterBottom>
                            {project.project}
                          </Typography>
                        </TableCell>
                        <TableCell align="right">
                          <Typography variant="body1" gutterBottom>
                            {project.completedLessonsCount}
                          </Typography>
                        </TableCell>
                      </TableRow>
                    ))}
                </TableBody>
              </Table>
            </Box>
          </Collapse>
        </TableCell>
      </TableRow>
    </>
  );
};

这里是为它生成的快照:

<body>
  <div>
    <tr
      class="MuiTableRow-root makeStyles-root-1"
    >
      <td
        class="MuiTableCell-root"
      >
        <button
          aria-label="expand row"
          class="MuiButtonBase-root MuiIconButton-root MuiIconButton-sizeSmall"
          tabindex="0"
          type="button"
        >
          <span
            class="MuiIconButton-label"
          >
            <svg
              aria-hidden="true"
              class="MuiSvgIcon-root MuiSvgIcon-fontSizeLarge"
              focusable="false"
              viewBox="0 0 24 24"
            >
              <path
                d="M7.41 8.59L12 13.17l4.59-4.58L18 10l-6 6-6-6 1.41-1.41z"
              />
            </svg>
          </span>
          <span
            class="MuiTouchRipple-root"
          />
        </button>
      </td>
      <th
        class="MuiTableCell-root"
        role="cell"
        scope="row"
      >
        <h5
          class="MuiTypography-root MuiTypography-h5"
        >
          Course1
        </h5>
      </th>
      <td
        class="MuiTableCell-root MuiTableCell-alignRight"
      >
        <h5
          class="MuiTypography-root MuiTypography-h5"
        >
          3
        </h5>
      </td>
    </tr>
    <tr
      class="MuiTableRow-root"
    >
      <td
        class="MuiTableCell-root"
        colspan="6"
        style="padding-bottom: 0px; padding-top: 0px;"
      />
    </tr>
  </div>
</body>

所以看起来问题出在&lt;body&gt; 内的&lt;div&gt; 元素,但我不知道如何解决该错误。我使用React.Fragment (&lt;&gt;) 来抓取TableRow 中的这两个,所以我认为&lt;div&gt; 不应该存在...

我从 material-ui 文档中获取的 Row 组件用于折叠表: https://material-ui.com/components/tables/

并且有它的代码和框代码(也来自文档): https://codesandbox.io/s/material-demo-forked-fnisr?file=/demo.js

@@更新

我不得不用&lt;table&gt;&lt;tbody&gt; 包装Row 组件。我为此创建了一个包装器。这是测试代码现在的样子:

const Wrapper: React.FC = ({ children }) => {
  return (
    <table>
      <tbody>{children}</tbody>
    </table>
  );
};

test('Basic render', () => {
  const component = render(
    <Wrapper>
      <Row course={props} />
    </Wrapper>
  );
  expect(component.baseElement).toMatchSnapshot();
});

【问题讨论】:

    标签: reactjs jestjs material-ui


    【解决方案1】:

    tr 元素必须有父 table 元素。所以,用表格包裹你的组件将解决这个问题。

    tr 不能是 div 元素的后代。

    【讨论】:

      【解决方案2】:

      在演示中,行被包装在表头或表体元素中,您还需要在组件中添加有效的上下文。

      tr 元素 can be used 所在的上下文:

      作为 thead 元素的子元素。
      作为 tbody 元素的子元素。
      作为 tfoot 元素的子元素。
      作为 table 元素的子元素,在任何 caption、colgroup 和 thead 元素之后,但前提是没有 tbody 元素是 table 元素的子元素。

      div 不是来自您的自定义Row 组件,而是来自您渲染&lt;Row /&gt; 的位置。

      【讨论】:

      • 我明白这一点。但是我在另一个包含Row 的组件中拥有所有这些。另一个组件的快照如下所示:&lt;table&gt;&lt;tbody&gt;&lt;Row&gt;&lt;/Row&gt;&lt;/tbody&gt;&lt;/table&gt;> 所以现在当我只想测试 Row 时出现问题,cos 测试不知道包装表元素的其余部分...
      • 我不知道你是如何测试它的。如果您的 DOM 结构在其他方面有效,您可以忽略错误或将组件安装在测试运行程序的有效上下文中。
      • 好吧,我忘了我可以在测试中的render()方法中添加一些html标签。我创建了一个包装器,它添加了&lt;table&gt;&lt;tbody&gt;。我添加到我的问题的更新部分。
      猜你喜欢
      • 2017-02-16
      • 2019-06-22
      • 2017-02-16
      • 1970-01-01
      • 2018-01-02
      • 2020-01-25
      • 2018-06-03
      • 2021-12-12
      • 2019-09-13
      相关资源
      最近更新 更多