React中children prop条件与非条件渲染的行为差异及原因
核心现象本质
两个场景的行为差异,本质是React的节点复用判定逻辑在起作用,和组件是“从外部传入的children”还是“在组件内部直接声明”没有直接关系。
- 非条件渲染场景下,你写在
<App>标签内部的<Child name="as children from root"/>,会在最顶层渲染入口执行时生成一个不可变的React元素对象,这个对象被作为children属性传给App组件。 - 当App因为内部state更新触发重渲染时,它只是把接收到的
children对象原样插入到自己的渲染输出里,全程没有自己生成新的Child元素。根据React的diff规则,如果同一位置上的前后两个元素是完全相同的对象引用,React会直接复用之前已经挂载好的组件实例,既不会触发组件的重新渲染,也不会卸载实例。这就是这个外部传入的Child不会跟着App重渲染走render流程的原因——它的实例归属于最顶层的渲染入口,只有顶层重新生成这个Child的元素时,它才会重渲染。
条件渲染时的卸载重挂载逻辑
很多人会误以为“外部传入的children会有特殊的保留逻辑”,实际上这个特性的前提是这个位置的节点一直稳定存在,没有被判定为消失。
在你写的条件渲染代码里,逻辑是:
{state%2===0 && <Child name="as children from app"/>} {state%2===0 && children}
这个表达式的返回值有两种完全不同的形态:
- 条件成立时:返回对应的有效Child元素对象
- 条件不成立时:短路返回
false
React做diff对比时,会按顺序检查同一层级的节点序列:
- 当state为偶数时,对应位置的节点是Child元素,React正常挂载该组件
- 当state变成奇数时,对应位置的节点返回
false,React直接判定该位置之前的Child节点被移除,执行卸载流程 - 当state再次变回偶数时,对应位置的节点又变回Child元素,但之前的实例已经被卸载,React找不到可复用的节点,就会重新挂载新的Child实例
这里的关键是:不管这个Child元素是App内部直接生成的,还是从外部传入的,只要它所在的位置在某次渲染中被返回成了空值(null、false、undefined),React就会把之前挂在这里的组件实例卸载掉。之前提到的“外部传入的children不随App重渲染”的特性,只是因为那个场景下节点一直稳定存在,没有被临时移除,不是说children本身有什么“免卸载”的特权。
通用结论
你的判断是成立的:
- 无论组件是以
children传入,还是在组件内部直接声明,只要在渲染过程中它所在的位置因为条件判断临时变成了空值,就一定会触发组件的卸载与重新挂载 - 反过来,只要组件所在的位置一直保持稳定的有效元素引用,没有被条件判断临时移除,那么不管它是外部传入的还是内部声明的,都不会因为父组件的重渲染触发多余的渲染流程,更不会被卸载。
开发小提示:如果需要在条件切换时保留组件状态、避免无意义的重挂载,不要用逻辑与直接把组件节点短路成空值,可以通过CSS的显隐属性(如
display: none)控制组件可见性,或者在列表渲染时给组件绑定稳定的key值,帮助React正确复用实例。
内容的提问来源于stack exchange,提问作者Lakshya Thakur
相关产品推荐
相关产品推荐

