背景

今天在写一个 react + material ui 的前端项目时,遇到一个组件报错问题,下面是报错图片:

查找元素发现,使用的 <Typography> 组件在不特别指明要渲染的元素前,会默认渲染成 p 元素,如果在组件里面嵌套了 div ,渲染出的就是 p 元素嵌套了 div. 这时 react 就会报出错误,但是为什么 react 不允许 p 元素嵌套 div 呢,这里有同学可能会说是因为 p 元素可能不是块元素吧,行元素里不能嵌套块元素,但事实上 p 元素也是块元素,行元素不能嵌套块元素只是规范定义,建议我们不这样用,因为会有 SEO 之类的问题,但是实际上用浏览器不会报错的,比如我用 span 尝试嵌套 div 都不会报错,于是,我查询了文档。
终于得到了答案。

原因

之所以会出现这个情况,是因为 p 元素的特殊性,它有”标签忽略的特性“我们先来看官方文档的解释

意思就是,如果 p 标签之后如果紧跟 address, article, aside, blockquote, details, div, dl, fieldset, figcaption, figure, footer, form, h1, h2, h3, h4, h5, h6, header, hgroup, hr, main, menu, nav, ol, p, pre, section, table, or ul等元素或者其 parent 元素中没有更多内容,并且 parent 元素是既不是 a, audio, del, ins, map, noscript, or video 元素,也不是一个自定义的元素的 HTML 元素就可以省略 p 的结束标签。

总结来说如果我们在 DOM 树中的 p 元素之中嵌套了 div 元素,并且 p 元素后面还有块元素之类的,p 元素嵌套的 div 元素就会渲染出两个元素。我们通过下图,举个例子来说,因为第一个 <p> 标签之后紧跟了一个 <div> 标签,其就可以省略闭合标签,而浏览器解析到真正的 p 元素的闭合标签 </p> ,发现它没有开始标签(前面的开始标签已经自动加上了闭合标签),于是就给他加了一个开始标签:</p>于是我们开始说的 p 元素嵌套 div 元素就渲染成了两个元素,会多出一个空的 p 元素:

最终渲染的代码就是这样:

1
2
3
4
5
6
7
8
9
10
<html>

<body>
<p>Test1
</p>
<div>Test2</div>
<p></p>
</body>

</html>

总结

于是,react 为了防止意外发生,限制了 p 元素不能嵌套 div 等块级元素,就会出现我们开始所说的报错。
我们可以在 stackoverflow 上看到很多解答,都是类似的问题。

Putting \<div> inside \<p> is adding an extra \<p> [duplicate]

Putting \<div> inside \<p> is adding an extra \<p> [duplicate]