首页
学习
活动
专区
圈层
工具
发布
首页
学习
活动
专区
圈层
工具
MCP广场
社区首页 >问答首页 >如何重写这个简单的组件树以利用React.memo?

如何重写这个简单的组件树以利用React.memo?
EN

Stack Overflow用户
提问于 2021-10-23 03:08:53
回答 1查看 71关注 0票数 1

在下面的码砂箱中,我们有一个<Child />组件,它可以在<div />中呈现,也可以不呈现,具体取决于状态。

代码语言:javascript
复制
import React, { useState, memo } from "react";

const Child = memo(
  ({ n }) => {
    console.log("Re-rendered child");
    return <span>Child {n}</span>;
  },
  () => true
);

export default function App() {
  const [shouldWrapChildComponent, setShouldWrapChildComponent] = useState(
    false
  );

  return (
    <div>
      <button
        onClick={() =>
          setShouldWrapChildComponent(
            (shouldWrapChildComponent) => !shouldWrapChildComponent
          )
        }
      >
        Toggle Wrapper
      </button>

      <br />

      {[0, 1, 2, 3, 4, 5].map((n) => {
        return shouldWrapChildComponent ? (
          <div>
            <Child n={n} />
          </div>
        ) : (
          <Child n={n} />
        );
      })}
    </div>
  );
}

如您所见,<Child />组件正在使用React.memo来防止重新呈现。

但是,当组件树更改时,不会阻止重新呈现(这是有意义的)。如果shouldWrapChildComponenttrue,那么<Child />将在<div />内部呈现,否则<Child />将呈现<div />过去呈现的位置。这就是我所说的“组件树改变”的意思。

是否有一种方法可以重写组件,使组件树不会改变,从而可以利用React.memo?或者,考虑到我们总是需要有条件地包装<Child />组件,那么没有办法保留<Child />的呈现输出

EN

回答 1

Stack Overflow用户

回答已采纳

发布于 2021-10-23 10:12:45

但是,当组件树更改时,不会阻止重新呈现(这是有意义的)。如果shouldWrapChildComponent为真,则将呈现在a的内部,否则将呈现用于呈现的位置。这就是我所说的“组件树改变”的意思。

让我们谈谈上面的引号,让我们做一个小小的更改,并删除div元素:

代码语言:javascript
复制
{[0, 1, 2, 3, 4, 5].map((n) => {
        return shouldWrapChildComponent ? (
          <Child n={n} />
        ) : (
          <Child n={n} />
        );
      })
}

结果是:即使在切换按钮之后,Child组件也只会重新呈现6次。您可以将console.log()放在App组件上并检查控制台,切换按钮将导致整个App重新呈现,但Child组件将不再重新呈现。

因此,render正在正确地工作,并防止子组件额外重呈现。

但是,当您用另一个元素(这里使用Child )包装您的div组件时,问题出现了,为什么?

为了检查这种行为,我通过创建一个resultArray变量来在呈现之前记录resultArray,从而将主体部分与返回方法分开。

代码语言:javascript
复制
import React, { useState, memo } from "react";

const Child = memo(
  ({ n }) => {
    console.log("Re-rendered child");
    return <span>Child {n}</span>;
  },
  () => true
);

export default function App() {
  const [shouldWrapChildComponent, setShouldWrapChildComponent] = useState(
    false
  );

  const resultArray = [0, 1, 2, 3, 4, 5].map((n) => {
        return shouldWrapChildComponent ? (
          <div>
            <Child n={n} />
          </div>
        ) : (
          <Child n={n} />
        );
      })

  console.log(`When shouldWrapChildComponent is ${shouldWrapChildComponent} the result array is: `, resultArray);

  return (
    <div>
      <button
        onClick={() =>
          setShouldWrapChildComponent(
            (shouldWrapChildComponent) => !shouldWrapChildComponent
          )
        }
      >
        Toggle Wrapper
      </button>
      <br />
      {resultArray}
    </div>
  );
}

resultArray shouldWrapChildComponentfalse

代码语言:javascript
复制
>(6) [Object, Object, Object, Object, Object, Object]

>0: Object
  type: "div"  // pay attention here
  key: null
  ref: null
  >props: Object
     n: 0         // ----> passing n via props to Child
  _owner: FiberNode
  _store: Object
>1: Object
>2: Object
>3: Object
>4: Object
>5: Object

resultArray shouldWrapChildComponent

代码语言:javascript
复制
>(6) [Object, Object, Object, Object, Object, Object]

>0: Object
  type: null    // pay attention here
  key: null
  ref: null
  >props: Object     // -----> passing a object instead of Child
    >children: Object
      >type: Object
        >type:   ƒ _c() {}
        >compare: f () {}
  _owner: FiberNode
  _store: Object
>1: Object
>2: Object
>3: Object
>4: Object
>5: Object

正如您所看到的,结果是完全不同的,所以react将触发每次重新呈现DOM中的新元素。

反应协调算法

当区分两棵树时,首先对两个根元素进行比较。根据根元素的类型,行为是不同的。

因此,当元素type被更改时,Reconciliation算法标记它并尝试重新呈现它,这个重呈现就像组件挂载之前在组件上的第一个呈现(并导致额外的子元素重呈现)。

更多关于反应官方文档

作为最简单的解决方案

有许多解决方案可以避免这种额外的重呈现,但作为一个简单的解决方案,您可以更改主要部分如下:

代码语言:javascript
复制
{[0, 1, 2, 3, 4, 5].map((n) => {
        return shouldWrapChildComponent ? (
          <div>
            <Child n={n} />
          </div>
        ) : (
          <div style={{display: "inline"}}>
            <Child n={n} />
          </div>
        );
      })
}
票数 2
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/69684810

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档