【问题标题】:React renders again the same div elements - Reconciliation questionReact 再次呈现相同的 div 元素 - 和解问题
【发布时间】:2020-03-10 13:12:05
【问题描述】:

在 React 文档中,我阅读了有关 reconciliation 的信息。我突然想到了以下有趣的场景。

在我的示例中,代码使用button 元素在点击事件上切换boolean 值。基于此,代码使用三元运算符决定 React 应该渲染哪个元素。

让我们有两个组件来表示我的示例:

const First = () => {
    return <div>element - no difference</div>
}

const Second = () => {
    return <div>element - no difference</div>
}

最后渲染的元素没有区别。

第一个例子

在第一个例子中有FirstSecond功能组件如下:

const YourComponent = () => {
    const [renderFirst, setRenderFirst] = useState(true);

    return <>
        <button onClick={() => setRenderFirst(!renderFirst)}>Toggle</button>
        {renderFirst ? <First /> : <Second /> }
    </>
}

第二个例子

在第二个示例中,仅使用 div 元素但以相同的结果结束:

const Contact = () => {
    const [renderFirst, setRenderFirst] = useState(true);

    return <>
        <button onClick={() => setRenderFirst(!renderFirst)}>Toggle</button>
        {renderFirst ? <div>element - no difference</div> : <div>element - no difference</div> }
    </>
}

问题

我对@9​​87654322@ 状态的理解:

只要根元素有不同的类型,React 就会拆除旧树并从头开始构建新树。

无论哪种方式,最终呈现的结果都会以&lt;div&gt;element - no difference&lt;/div&gt; 结尾。 第二个例子显然没有再次渲染 DOM 元素。

那么为什么 React 会渲染 第一个示例?在这种情况下,它们被认为是不同的类型吗?

谢谢!

【问题讨论】:

    标签: javascript reactjs


    【解决方案1】:

    通过 rendering 我假设您的意思是要“渲染”也就是 committed 到 DOM 的更改。在这两个示例中仍将触发对帐过程。

    答案很简单。在第一个示例中,您返回一个 React component&lt;First /&gt;&lt;Second /&gt;),而在第二个示例中,您返回一个 React element(两个 @ 987654324@'s)。

    React 无法事先知道你的两个组件中的每一个会做什么(它们可能有自己的逻辑),所以在后一种情况下,React 只会看到你想用 Second 替换 First,然后重新使成为。在前一种情况下,您只返回可以客观比较的元素

    【讨论】:

    • 我误解了这个问题吗?否决者能否澄清这个答案的坏处?
    • 我相信 OP 的假设是错误的,在这两种情况下,DOM 都会再次呈现,至少如果你能证明不是这样的话。因此,我认为声称示例不同是错误的。
    • @DennisVash,通过“渲染”我相信 OP 意味着将更改提交给 DOM。由于状态变量已更改,因此当然仍会触发对帐过程。但是,在第二个示例中,div“实例”不会改变 - div 将保留。在第一个示例中,之前的 div 将被替换为相同但新的。
    • 请证明“但是,在第二个示例中,div“实例”不会改变 - div 将保持不变。是事实。据我检查,有一个不同的实例。
    • @DennisVash 当然,这是一个快速分叉codesandbox.io/s/react-hooks-counter-demo-itb6h。检查div 并设置,例如color: red,然后切换元素 - 样式保持不变。现在渲染 Contact2 并执行相同操作 - 元素被替换为新的 div 并且样式消失。
    【解决方案2】:

    除了@Chrisanswers之外,我做了一个小测试来验证答案。

    我的主要考虑是JSX 是否会生成一个新实例,尽管组件可能会因条件而被卸载。

    import React, { useState, useEffect, useRef } from 'react';
    import ReactDOM from 'react-dom';
    
    // You can check either
    const Component = <div>element - no difference</div>;
    
    const Contact = () => {
      const [renderFirst, setRenderFirst] = useState(true);
      const componentRef = useRef();
      const first = useRef();
    
      useEffect(() => {
        console.log(componentRef.current);
    
        const [child] = componentRef.current.children;
    
        if (!first.current) {
          first.current = child;
        }
      }, []);
    
      useEffect(() => {
        const [child] = componentRef.current.children;
        console.log(child !== first.current ? 'different' : 'same');
      });
    
      return (
        <>
          <button onClick={() => setRenderFirst(prev => !prev)}>Toggle</button>
          <div ref={componentRef}>
            {renderFirst ? (
              <div>element - no difference</div>
            ) : (
              <div>element - no difference</div>
            )}
            {/* {renderFirst ? Component : Component} */}
          </div>
        </>
      );
    };
    
    ReactDOM.render(<Contact />, document.getElementById('root'));
    

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 2022-01-14
      • 1970-01-01
      • 2017-10-15
      • 1970-01-01
      • 1970-01-01
      • 2020-10-13
      • 2013-09-07
      相关资源
      最近更新 更多