为什么React会丢弃整个DOM子树并从头开始重新创建它?

Dan*_*iel 7 javascript reactjs

有两个可用于在渲染时添加内容的助手:

  ...

  const DisplayA = () => <div className={'containerA'}>
    <button onClick={handleToggleA}>{"A toggled: " + toggledA.toString()}</button>
  </div>

  const displayB = () => <div className={'containerB'}>
    <button onClick={handleToggleB}>{"B toggled: " + toggledB.toString()}</button>
  </div>

  return (
    <>
      <DisplayA />
      { displayB() }
    </>
  );

  ...
Run Code Online (Sandbox Code Playgroud)

问题在于,在第一个帮助程序中,React总是丢弃整个子树,然后从头开始再次创建它,如下面所示:

子树被丢弃并重新创建

演示

我知道,第一种方法是React.createElement的语法糖,因此每个渲染都会创建一个新组件。但是,第二种方式是,每个渲染也创建一个独特的箭头函数。

  1. 为什么React不知道如何以第一种方式重用子树,但是知道第二种方式?幕后发生什么?

  2. 我们如何发现DOM子树何时被丢弃并在每个渲染中重新创建?假设不应该创建内联组件并且仅使用内联函数就足够了吗?

注意,助手可以来自道具,例如(渲染道具模式)。

ggo*_*van 5

这将取决于DisplayA定义的范围。功能组件通常应定义在文件的顶层。在您的演示中DisplayA,组件是在 of 内部创建的renderApp因此每次App渲染时都会创建一个新的功能组件,而不是对同一组件进行新的调用。

要解决此问题,请DisplayA在文件中设置顶层并将道具传递给它。

const DisplayA = ({handleToggle, toggled}) => <div className={'containerA'}>
  <button onClick={handleToggle}>{"A toggled: " + toggled.toString()} </button>
</div>

const App = () => {
  ...
  return <>
    <DisplayA handleToggle={() => {...}} toggle={...} />
  </>
}
Run Code Online (Sandbox Code Playgroud)

第二种方法不会创建一个传递给 React 进行协调的组件,而是一个在渲染时调用的函数,并将包含的元素放入该组件的渲染中。