3
头图

Straight to the point, let's first look at a bug map (there is a 00 below the status).
image
The expectation is: when the state is 0, the two components do not render.
Status: When the state is 0, the two components are not rendered, but 00 is rendered.

  • Zero rendering bug code
  • How to Fix Zero Rendering Issues
  • First look at the source code
  • Source code doubts
  • Reason summary
  • source code hammer

Zero rendering bug code

What is React's zero rendering issue?
Take a look at the following code, we will often write it like this:

// bug代码 0
{obj?.count && <span>{obj?.count}</span>}

If obj?.count is 0, the rendering result is 0.
Isn't there just one 0 here, why is it 00 above?

// bug代码 00 
{obj?.countFoo && <span>{obj?.countFoo}</span>}
{obj?.countBar && <span>{obj?.countBar}</span>}

When both obj?.countFoo and obj?.countBar are 0, the rendering result is 00.

How to Fix Zero Rendering Issues

{!!obj?.count && <span>{obj?.count}</span>}

or

{obj?.count ? <span>{obj?.count}</span> : null}

or

{Boolean(obj?.count) && <span>{obj?.count}</span>}

First look at the source code

Reason (click the type to view the source code):
The React component will render string, number . Will not render null , undefined , boolean .

Source code doubts

Since boolean will be treated as null, why does true && <FooComponent /> render normally?
Let’s talk about the conclusion first, because of the && operation, React finally renders jsx and the calculated result.

const type = typeof children;
if (type === 'undefined' || type === 'boolean') {
    // All of the above are perceived as null.
    children = null;
}

That is to say, the children of here is the result of jsx calculation.

An example is as follows:

// 可渲染值
1 && <FooComponent /> // => jsx计算结果为<FooComponent />,因此渲染<FooComponent/>
"a string" && <FooComponent /> // => jsx计算结果为<FooComponent />,因此渲染<FooComponent />
0 && <FooComponent /> // => jsx计算结果为0,Renders '0'
true && <FooComponent /> // => jsx计算结果为<FooComponent />,因此渲染<FooComponent />

// 不可渲染值
false && <FooComponent /> // => jsx计算结果为false,因此什么都不渲染
null && <FooComponent /> // => jsx计算结果为null,因此什么都不渲染
undefined && <FooComponent /> // => jsx计算结果为undefined,因此什么都不渲染

Reason summary

In fact, it is not the problem of React rendering at all, but the problem of the return value after the && operator.
Therefore, the most fundamental reason is that

  • React render string, number, normal component
  • React doesn't render undefined, boolean, null

    {"1"} // 渲染为"1"
    {0} // 渲染为0
    {<FooComponent />} // 假设为正常组件,渲染为<FooComponent />
    
    {undefined} // 不渲染
    {true} // 不渲染
    {false} // 不渲染
    
    {null} // 不渲染

source code hammer

  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;
        }
    }
  }

The original value is null, and undefined and boolean are finally processed as null. React does not render the source code of null. What about ?

  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 '';
      }

For html tags to render empty strings, empty strings will be rendered, for example <div>""</div> will be rendered as <div>""</div>
But for react the full flow is {null} =>{""} => nothing
For example the following:

<div>{''}</div> // => <div></div>
<div>{'    '}</div> // => <div>    </div>

So, How does React handle empty strings?

export function pushTextInstance(
  target: Array<Chunk | PrecomputedChunk>,
  text: string,
  responseState: ResponseState,
): void {
  if (text === '') {
    // Empty text doesn't have a DOM node representation and the hydration is aware of this.
    // 这句注释的意思是:空文本节点没有DOM节点表示,它属于textNode
    return;
  }
  // TODO: Avoid adding a text separator in common cases.
  target.push(stringToChunk(encodeHTMLTextNode(text)), textSeparator);
}

From the source code, we can see that for empty text nodes, React will return directly, and will not generate a text instance (TextInstance).

Looking forward to communicating with you and making progress together:

  • WeChat public account: Dada big front end / excellent_developers
  • Front-end Q&A mutual aid planet: t.zsxq.com/yBA2Biq

趁你还年轻
4.1k 声望4.1k 粉丝