React的零渲染问题及源码分析

开门见山,先来看一张bug图(状态下面有个00)。
React的零渲染问题及源码分析
文章图片

预期是:状态为0时,2个组件不做渲染。
现状:状态为0时,2个组件不做渲染,但是渲染出了00。

  • 零渲染 bug 代码
  • 如何修复零渲染问题
  • 初窥源码
  • 源码疑惑
  • 原因总结
  • 源码实锤
零渲染 bug 代码 什么是React的零渲染问题?
看下下面这段代码,我们会经常这样写:
// bug代码 0 {obj?.count && {obj?.count}}

假如obj?.count为0,渲染结果为0。
这里不就1个0么,上面为什么是00呢。
// bug代码 00 {obj?.countFoo && {obj?.countFoo}} {obj?.countBar && {obj?.countBar}}

当obj?.countFoo和obj?.countBar都为0时,渲染结果为00。
如何修复零渲染问题
{!!obj?.count && {obj?.count}}

或者
{obj?.count ? {obj?.count} : null}

或者
{Boolean(obj?.count) && {obj?.count}}

初窥源码 原因(点击类型查看源码):
React组件会渲染string,number。不会渲染null,undefined,boolean。
源码疑惑 既然boolean会被处理为null,那为什么true && 可以正常渲染呢?
先说结论,因为进行了&&运算,React最终渲染的是jsx与计算后的结果。
const type = typeof children; if (type === 'undefined' || type === 'boolean') { // All of the above are perceived as null. children = null; }

也就是说 此处的children,是jsx计算后的结果。
举例如下:
// 可渲染值 1 && // => jsx计算结果为,因此渲染 "a string" && // => jsx计算结果为,因此渲染 0 && // => jsx计算结果为0,Renders '0' true && // => jsx计算结果为,因此渲染// 不可渲染值 false && // => jsx计算结果为false,因此什么都不渲染 null && // => jsx计算结果为null,因此什么都不渲染 undefined && // => jsx计算结果为undefined,因此什么都不渲染

原因总结 其实,根本不是React渲染什么的问题,而是&&操作符后返回值的问题。
所以,最根本是因为
  • React渲染string,number,正常组件
  • React不渲染undefined,boolean,null
    {"1"} // 渲染为"1" {0} // 渲染为0 {} // 假设为正常组件,渲染为{undefined} // 不渲染 {true} // 不渲染 {false} // 不渲染{null} // 不渲染

源码实锤
const type = typeof children; // React不渲染undefined,boolean if (type === 'undefined' || type === 'boolean') { // All of the above are perceived as null. children = null; }let invokeCallback = false; if (children === null) { invokeCallback = true; } else { switch (type) { case 'string': case 'number': // React渲染string,number invokeCallback = true; break; case 'object': // React渲染正常组件 switch ((children: any).$$typeof) { case REACT_ELEMENT_TYPE: case REACT_PORTAL_TYPE: invokeCallback = true; } } }

原始值为null,和undefined以及boolean最终被处理为null,React不渲染null的源码实锤呢?
源码地址:https://github.com/facebook/r...
render( child: ReactNode | null, context: Object, parentNamespace: string, ): string { if (typeof child === 'string' || typeof child === 'number') { const text = '' + child; if (text === '') { return ''; } this.previousWasTextNode = true; return escapeTextForBrowser(text); } else { let nextChild; ({child: nextChild, context} = resolve(child, context, this.threadID)); // React不渲染null if (nextChild === null || nextChild === false) { return ''; }

【React的零渲染问题及源码分析】对于html标签渲染空字符串而言,空字符串会被忽略。
例如""会被渲染为
完整流程为{null} =>{""} => nothing

    推荐阅读