Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

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

Open
yanlele opened this issue Jul 12, 2024 · 0 comments
Labels
TOP100互联网 公司标签 web框架 web 框架相关知识
Milestone

Comments

@yanlele
Copy link
Member

yanlele commented Jul 12, 2024

关键词: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 中传递过于复杂或频繁变化的数据,以减少不必要的渲染次数。

@yanlele yanlele added TOP100互联网 公司标签 web框架 web 框架相关知识 labels Jul 12, 2024
@yanlele yanlele added this to the milestone Jul 12, 2024
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
TOP100互联网 公司标签 web框架 web 框架相关知识
Projects
None yet
Development

No branches or pull requests

1 participant