[React] 如何避免使用 context 的时候, 引起整个挂载节点树的重新渲染【热度: 420】

关键词:React Context 渲染问题

要避免在 React 开发中使用 context 时引起整个挂载节点树的重新渲染,可以采取以下方法:

  1. React Context 数据分割:把提供 context value 的部分提取到单独的组件中,并且仅在该组件中修改 context value。这样,当 context value 变化时,只有真正使用该 context 的消费组件会重新渲染,而非所有挂载节点都会重新渲染。

假设我们有一个应用,需要管理主题颜色和用户信息两个不同的数据。

首先,创建两个 Context:

import React from "eact";

// 创建主题颜色 Context
const ThemeContext = React.createContext({ theme: "light" });

// 创建用户信息 Context
const UserContext = React.createContext({ user: null });

在顶层组件中,提供这两个 Context 的 Provider,并设置相应的值:

class App extends React.Component {
  state = {
    theme: "dark",
    user: { name: "John Doe", age: 25 },
  };

  render() {
    return (
      <ThemeContext.Provider value={this.state.theme}>
        <UserContext.Provider value={this.state.user}>
          <Toolbar />
        </UserContext.Provider>
      </ThemeContext.Provider>
    );
  }
}

然后,在需要使用主题颜色的组件中,可以通过以下方式获取:

class ThemedButton extends React.Component {
  static contextType = ThemeContext;

  render() {
    const theme = this.context;
    return <Button theme={theme} />;
  }
}

在需要使用用户信息的组件中,同样方式获取:

class UserProfile extends React.Component {
  static contextType = UserContext;

  render() {
    const user = this.context;
    return (
      <div>
        <p>用户名:{user.name}</p>
        <p>年龄:{user.age}</p>
      </div>
    );
  }
}

在上述例子中,我们将主题颜色和用户信息分割到不同的 Context 中。ThemeContext 用于传递主题相关的数据,UserContext 用于传递用户相关的数据。这样,不同的组件可以根据自己的需求订阅相应的 Context,获取所需的数据,而不会相互干扰。每个组件只需要关注自己所使用的 Context,提高了代码的可读性和可维护性。同时,当某个 Context 的数据发生变化时,只有订阅了该 Context 的组件才会重新渲染,避免了不必要的重新渲染。

  1. 对消费组件使用 React.memo() 进行包裹:React.memo 可以对函数组件进行浅比较,如果组件的 props 没有变化,就不会触发重新渲染。通过将消费 context 的组件用 React.memo() 包裹,可以避免不必要的重新渲染。

例如,假设有一个 ContextProvider 组件提供 context value,以及一个使用该 context 的子组件 ConsumerComponent,优化后的代码可能如下所示:

const ContextProvider = ({ children }) => {
  // 管理 context value 的状态
  const [value, setValue] = useState(/* 初始值 */);

  return <MyContext.Provider value={value}>{children}</MyContext.Provider>;
};

const ConsumerComponent = React.memo(({ contextValue }) => {
  // 仅根据 context value 进行渲染或处理逻辑
  return <div>{/* 使用 context value 的相关逻辑 */}</div>;
});

在上述示例中,ContextProvider 负责管理 context value 的状态变化,而 ConsumerComponent 是使用 context 的消费组件,并通过 React.memo() 进行了包裹。这样,当 value 发生变化时,只有 ConsumerComponent 会根据浅比较来决定是否重新渲染,而不是整个挂载节点树都重新渲染。

通过以上方式,可以减少使用 context 时不必要的重新渲染,提高应用的性能。但具体的优化策略还需要根据项目的实际情况进行选择和调整。同时,还需注意避免在 context 中传递过于复杂或频繁变化的数据,以减少不必要的渲染次数。