使用控制反转代替React.memo解决重复渲染问题

124 阅读2分钟

背景

在平时的开发中,有这样一种场景,父组件引用了子组件,父组件里使用了useState,但state并未传递给子组件,当state更新时子组件也更新了,如下:

//~ index.js 父组件
import { useState } from "react"
import Chilren from "./children"

const Father = () => {
  const [count, setCount] = useState(0);
  console.log("Father rendered");
  return (
    <>
      <p>I am Father p tag, {count}</p>
      <button onClick={() => setCount(count + 1)}>Add Count</button>
      <br />
      <Children />
    </>
  );
};

export default Father;
// ~ children.js 子组件
const Children = () => {
  console.log("Children rendered");
  return <p>I am Children p tag</p>;
};

export default Children;

如果要避免Children重复渲染,通常采用的方式是用React.memo包裹子组件,如下:

// ~ children.js 子组件
import React from "react";

const Children = () => {
  console.log("Children rendered");
  return <p>I am Children p tag</p>;
};

export default React.memo(Children);

这种方式确实可以解决子组件重复渲染的问题,但大多数人在开发时比较容易忽略这种问题,且如果子组件很多时,需要在每个子组件里都用React.memo包裹,非常麻烦。这时主角就登场了,通过控制反转可以很方便解决解决这个问题。

什么是控制反转

在使用之前我们先来简单介绍一下什么是控制反转,控制反转(Inversion of Control)是一种是面向对象编程中的一种设计原则,用来减低计算机代码之间的耦合度。其基本思想是:借助于“第三方”实现具有依赖关系的对象之间的解耦。如下图,原先对象A、B、C、D内部逻辑相互依赖,耦合性高,通过引入IOC容器,把依赖的逻辑放入IOC容器里,对象A、B、C、D就达到解耦的目的。

控制反转webp

通过控制反转解决重复渲染问题

这时你也许会好奇,控制反转不是用来解耦的吗,咋解决重复渲染问题呢?话不多说,我们通过以下代码来看

//~ index.js 父组件
import { useState } from "react";

const FatherIoc = ({ children }) => {
  const [count, setCount] = useState(0);
  return (
    <>
      <p>I am Father p tag, {count}</p>
      <button onClick={() => setCount(count + 1)}>Add Count</button>
      {children}
    </>
  );
};

const Father = () => {
  console.log("Father rendered");
  return (
    <FatherIoc>
      <br />
      <Children />
    </FatherIoc>
  );
};

export default Father;
// ~ children.js 子组件
import React from "react";

const Children = () => {
  console.log("Children rendered");
  return <p>I am Children p tag</p>;
};

export default Children;

把父组件引用useState的逻辑放入FatherIoc容器中,父组件仅负责渲染子组件,父组件通过插槽的方式插入FatherIoc容器,这样无论state如何更新,子组件始终只渲染一次,无论父组件添加了多少个子组件,子组件也无需判断是否要加入React.memo,是不是非常完美呢。

### 参考文章

为什么 React 中使用控制反转不会触发重新渲染 - 掘金