WHAT - React Context 两层组件的优化机制

一、Context

官方文档:https://react.dev/learn/passing-data-deeply-with-context

二、分离逻辑和视图

在 React 中使用两层组件来使用 Context 的原因主要是为了分离逻辑和视图,并且更好地管理和优化状态。

这种模式通常被称为“Context Provider/Consumer”模式。

以下是一些具体原因:

  1. 解耦状态逻辑和视图逻辑

    • Context Provider 组件通常负责管理和提供状态。它包含与状态管理相关的逻辑,例如获取数据、处理状态变化等。
    • Consumer 组件 负责渲染与状态相关的视图。它通过 Context 访问 Provider 提供的状态,从而保持视图逻辑的简洁和易维护。
  2. 提高组件的可复用性

    • 使用 Provider 和 Consumer 分离逻辑和视图后,可以更容易地在不同的视图组件中复用相同的状态逻辑,而无需重复编写相同的代码。
  3. 优化性能

    • Context 的更新会触发使用了这个 Context 的所有组件重新渲染。通过分层结构,可以在 Provider 中集中处理状态更新,减少不必要的重新渲染,提高性能。
    • Consumer 组件可以根据需要细粒度地订阅 Context 的某些部分,避免不必要的渲染。
  4. 简化测试

    • 逻辑和视图的分离使得单元测试更加简单。Provider 组件可以独立测试其状态管理逻辑,而 Consumer 组件可以通过模拟的 Context 值来测试其渲染逻辑。
  5. 增强代码的可维护性和可读性

    • 使用两层组件可以使代码结构更加清晰,职责分离明确。状态管理和 UI 逻辑分别处理,使得代码更容易理解和维护。

一个典型的使用示例如下:

// 创建 Context
const MyContext = React.createContext();

// Provider 组件
const MyProvider = ({ children }) => {
  const [state, setState] = useState(initialState);

  const value = {
    state,
    updateState: (newState) => setState(newState),
  };

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

// Consumer 组件
const MyConsumer = () => {
  const { state, updateState } = useContext(MyContext);

  return (
    <div>
      <p>Current state: {state}</p>
      <button onClick={() => updateState("new state")}>Update State</button>
    </div>
  );
};

// 使用 Provider 包裹应用
const App = () => (
  <MyProvider>
    <MyConsumer />
  </MyProvider>
);

export default App;

通过这种方式,Provider 组件管理状态逻辑,Consumer 组件专注于渲染逻辑,从而实现了状态逻辑和视图逻辑的分离。

三、优化性能

  • Context 的更新会触发使用了这个 Context 的所有组件重新渲染。通过分层结构,可以在 Provider 中集中处理状态更新,减少不必要的重新渲染,提高性能。
  • Consumer 组件可以根据需要细粒度地订阅 Context 的某些部分,避免不必要的渲染。

这段话解释了 Context 的工作机制以及如何优化组件的渲染行为。具体来说,当 Context 的值发生变化时,所有使用 useContext 获取该 Context 的组件都会重新渲染,即使这些组件使用了 React.memoshouldComponentUpdate 来优化性能。这是因为 Context 的变化会绕过这些优化机制。

为了避免这种情况,可以将组件分为两个部分:一个外层组件从 Context 中读取所需的内容,并将这些内容作为 props 传递给使用 React.memo 优化的子组件。这样,只有当与子组件相关的 Context 值发生变化时,子组件才会重新渲染。

下面是一个示例代码和解释:

示例代码

import React, { useContext, useState, createContext, memo } from 'react';

// 创建 Context
const MyContext = createContext();

const MyProvider = ({ children }) => {
  const [state, setState] = useState({ count: 0, name: 'John' });

  return (
    <MyContext.Provider value={{ state, setState }}>
      {children}
    </MyContext.Provider>
  );
};

// 外层组件,从 Context 中读取所需内容
const OuterComponent = () => {
  const { state } = useContext(MyContext);
  
  // 只提取与子组件相关的值
  const name = state.name;

  return <InnerComponent name={name} />;
};

// 子组件,使用 memo 优化
const InnerComponent = memo(({ name }) => {
  console.log('InnerComponent render');
  return <div>Name: {name}</div>;
});

const App = () => (
  <MyProvider>
    <OuterComponent />
    <button onClick={() => setState((prev) => ({ ...prev, count: prev.count + 1 }))}>
      Increment Count
    </button>
  </MyProvider>
);

export default App;

解释

  1. 创建 Context:我们创建了一个 Context MyContext,并使用 MyProvider 组件来提供 Context 的值。

  2. MyProvider 组件MyProvider 组件管理状态 state,包含 countname,并将其提供给 Context。

  3. OuterComponent 组件OuterComponent 组件使用 useContext 钩子从 Context 中读取状态 state。然后,它提取出与子组件相关的 name 值,并将其作为 props 传递给 InnerComponent

  4. InnerComponent 组件InnerComponent 组件使用 React.memo 进行优化。由于它只接收 name 作为 props,因此只有在 name 发生变化时,它才会重新渲染。

  5. 避免不必要的重新渲染:通过将 OuterComponent 作为中间层,从 Context 中读取值并将其传递给子组件,可以避免 InnerComponentcount 值变化时重新渲染,因为 InnerComponentcount 的变化不感兴趣。

这样,通过将组件分为两个部分,确保只有与子组件相关的 Context 值变化时才会触发子组件的重新渲染,从而优化性能。

相关推荐

  1. WHAT - React Context 组件优化机制

    2024-07-22 23:38:04       14 阅读
  2. react 父子组件渲染机制 | 优化手段

    2024-07-22 23:38:04       31 阅读
  3. react-创建组件种方式

    2024-07-22 23:38:04       33 阅读
  4. 常用系统安全机制

    2024-07-22 23:38:04       15 阅读
  5. 个五决策树和一个十决策树区别

    2024-07-22 23:38:04       45 阅读
  6. 14、应用优化

    2024-07-22 23:38:04       45 阅读

最近更新

  1. docker php8.1+nginx base 镜像 dockerfile 配置

    2024-07-22 23:38:04       49 阅读
  2. Could not load dynamic library ‘cudart64_100.dll‘

    2024-07-22 23:38:04       53 阅读
  3. 在Django里面运行非项目文件

    2024-07-22 23:38:04       42 阅读
  4. Python语言-面向对象

    2024-07-22 23:38:04       53 阅读

热门阅读

  1. Codeforces 923 div3 A-G

    2024-07-22 23:38:04       8 阅读
  2. go语言UTC时间转换为中国时间

    2024-07-22 23:38:04       10 阅读
  3. 《Nginx核心技术》第04章:生成缩略图

    2024-07-22 23:38:04       14 阅读
  4. 大模型日报 2024-07-22

    2024-07-22 23:38:04       15 阅读
  5. 超市111

    超市111

    2024-07-22 23:38:04      13 阅读
  6. PHP 快速入门:构建动态网站的基础

    2024-07-22 23:38:04       13 阅读
  7. 2024年7月16日~2024年7月22日周报

    2024-07-22 23:38:04       17 阅读
  8. Python面试题-11

    2024-07-22 23:38:04       12 阅读
  9. Redis小结

    2024-07-22 23:38:04       15 阅读
  10. SpringBoot中如何使用RabbitMq

    2024-07-22 23:38:04       11 阅读
  11. 【Python】Pandas简要教程

    2024-07-22 23:38:04       15 阅读
  12. 0基础认识C语言(函数)

    2024-07-22 23:38:04       17 阅读
  13. Gradle构建加速:自定义缓存策略全解析

    2024-07-22 23:38:04       14 阅读