【react】状态管理Context

目录

[一、Context 的核心概念](#一、Context 的核心概念)

[1. 什么是 Context?](#1. 什么是 Context?)

[2. 核心三要素:](#2. 核心三要素:)

二、使用场景分析

[适合场景 ✅](#适合场景 ✅)

[不适合场景 ❌](#不适合场景 ❌)

三、完整使用示例

[1. 创建 Context](#1. 创建 Context)

[2. 提供 Context](#2. 提供 Context)

[3. 消费 Context](#3. 消费 Context)

四、context使用详解

[1.Context.Consumer 使用详解](#1.Context.Consumer 使用详解)

[1. 基础用法(类组件)](#1. 基础用法(类组件))

[2. 嵌套 Consumer(多 Context)](#2. 嵌套 Consumer(多 Context))

[2、useContext 使用详解](#2、useContext 使用详解)

[1. 基础用法(函数组件)](#1. 基础用法(函数组件))

[2. 复杂对象消费](#2. 复杂对象消费)

3、对比总结

4、高级模式示例

[1. 自定义 Hook 封装](#1. 自定义 Hook 封装)

[2. 类组件中使用 Context(两种方式)](#2. 类组件中使用 Context(两种方式))

5、常见错误示例

[1. 未提供 Provider](#1. 未提供 Provider)

[2. 直接传递对象导致重复渲染](#2. 直接传递对象导致重复渲染)

五、性能优化策略

六、常见问题解决方案

[1. 默认值不生效?](#1. 默认值不生效?)

[2. 组件不更新?](#2. 组件不更新?)

[3. 多个 Context 如何管理?](#3. 多个 Context 如何管理?)

[4. Class 组件如何使用?](#4. Class 组件如何使用?)

[七、Context vs Redux](#七、Context vs Redux)

八、最佳实践


一、Context 的核心概念

1. 什么是 Context?

  • React 官方提供的跨层级组件通信方案

  • 解决 props drilling(深层级 props 传递)问题

  • 适合全局共享数据(如主题、用户身份、语言等)

2. 核心三要素:

  1. React.createContext()

    创建 Context 对象,可指定默认值

    TypeScript 复制代码
    const ThemeContext = React.createContext('light');
  2. Context.Provider

    数据提供者组件,通过 value 属性传递数据

    TypeScript 复制代码
    <ThemeContext.Provider value="dark">
      <App />
    </ThemeContext.Provider>
  3. Context.ConsumeruseContext

    数据消费者,用于获取上下文值

    TypeScript 复制代码
    // 类组件
    <ThemeContext.Consumer>
      {value => <div>{value}</div>}
    </ThemeContext.Consumer>
    
    // 函数组件
    const theme = useContext(ThemeContext);

二、使用场景分析

适合场景 ✅
  1. 全局主题切换

  2. 用户认证信息共享

  3. 多语言国际化

  4. 全局配置参数

  5. 跨 3+ 层组件的数据传递

不适合场景 ❌
  1. 高频更新数据(优先考虑状态管理库如 Redux)

  2. 简单父子组件通信(直接用 props)

  3. 组件内部私有状态(使用 useState)

三、完整使用示例

1. 创建 Context
TypeScript 复制代码
// ThemeContext.js
import { createContext } from 'react';

const ThemeContext = createContext({
  theme: 'light',
  toggleTheme: () => {},
});

export default ThemeContext;
2. 提供 Context
TypeScript 复制代码
// App.jsx
import { useState } from 'react';
import ThemeContext from './ThemeContext';
import Toolbar from './Toolbar';

export default function App() {
  const [theme, setTheme] = useState('light');

  const toggleTheme = () => {
    setTheme(prev => (prev === 'light' ? 'dark' : 'light'));
  };

  return (
    <ThemeContext.Provider value={{ theme, toggleTheme }}>
      <Toolbar />
    </ThemeContext.Provider>
  );
}
3. 消费 Context
TypeScript 复制代码
// Toolbar.jsx
import { useContext } from 'react';
import ThemeContext from './ThemeContext';

export default function Toolbar() {
  const { theme, toggleTheme } = useContext(ThemeContext);

  return (
    <div style={{ background: theme === 'dark' ? '#333' : '#fff' }}>
      <button onClick={toggleTheme}>
        Toggle Theme ({theme})
      </button>
    </div>
  );
}

四、context使用详解

1.Context.Consumer 使用详解

1. 基础用法(类组件)
TypeScript 复制代码
import React from 'react';

// 创建 Context
const ThemeContext = React.createContext('light');

// 类组件中使用 Consumer
class ThemedButton extends React.Component {
  render() {
    return (
      <ThemeContext.Consumer>
        {(theme) => (
          <button style={{ 
            background: theme === 'dark' ? '#333' : '#fff',
            color: theme === 'dark' ? '#fff' : '#333'
          }}>
            {this.props.children}
          </button>
        )}
      </ThemeContext.Consumer>
    );
  }
}

// Provider 设置
function App() {
  return (
    <ThemeContext.Provider value="dark">
      <ThemedButton>Click me</ThemedButton>
    </ThemeContext.Provider>
  );
}
2. 嵌套 Consumer(多 Context)
TypeScript 复制代码
const ThemeContext = React.createContext('light');
const UserContext = React.createContext('Guest');

function Toolbar() {
  return (
    <ThemeContext.Consumer>
      {(theme) => (
        <UserContext.Consumer>
          {(user) => (
            <div style={{ 
              background: theme, 
              padding: '10px' 
            }}>
              Logged in as: {user}
            </div>
          )}
        </UserContext.Consumer>
      )}
    </ThemeContext.Consumer>
  );
}

// Provider 嵌套
function App() {
  return (
    <ThemeContext.Provider value="dark">
      <UserContext.Provider value="Alice">
        <Toolbar />
      </UserContext.Provider>
    </ThemeContext.Provider>
  );
}

2、useContext 使用详解

1. 基础用法(函数组件)
TypeScript 复制代码
import React, { useContext } from 'react';

const ThemeContext = React.createContext('light');

function ThemedButton() {
  // 使用 useContext 获取值
  const theme = useContext(ThemeContext);

  return (
    <button style={{ 
      background: theme === 'dark' ? '#333' : '#fff',
      color: theme === 'dark' ? '#fff' : '#333'
    }}>
      Click me
    </button>
  );
}

// 动态更新示例
function App() {
  const [theme, setTheme] = React.useState('light');

  return (
    <ThemeContext.Provider value={theme}>
      <ThemedButton />
      <button onClick={() => setTheme(t => t === 'light' ? 'dark' : 'light')}>
        Toggle Theme
      </button>
    </ThemeContext.Provider>
  );
}
2. 复杂对象消费
TypeScript 复制代码
const UserContext = React.createContext({
  name: 'Guest',
  role: 'user',
  login: () => {}
});

function UserPanel() {
  // 解构获取多个值
  const { name, role, login } = useContext(UserContext);

  return (
    <div>
      <p>Name: {name}</p>
      <p>Role: {role}</p>
      <button onClick={login}>Login</button>
    </div>
  );
}

function App() {
  const [user, setUser] = React.useState({
    name: 'Alice',
    role: 'admin'
  });

  const loginHandler = () => {
    setUser({ name: 'Bob', role: 'editor' });
  };

  return (
    <UserContext.Provider value={{
      ...user,
      login: loginHandler
    }}>
      <UserPanel />
    </UserContext.Provider>
  );
}

3、对比总结

特性 Context.Consumer useContext
组件类型 适用于类组件 仅适用于函数组件
代码简洁性 需要嵌套函数 直接返回值,代码更简洁
多 Context 使用 需要多层嵌套 Consumer 可多次调用 useContext
动态更新 自动响应 Provider 更新 自动响应 Provider 更新
性能优化 需注意避免不必要的渲染 结合 memo 使用更易优化

4、高级模式示例

1. 自定义 Hook 封装
TypeScript 复制代码
// 创建自定义 Hook
function useTheme() {
  const context = useContext(ThemeContext);
  if (!context) {
    throw new Error('useTheme must be used within a ThemeProvider');
  }
  return context;
}

// 使用自定义 Hook
function ThemeToggle() {
  const { theme, toggleTheme } = useTheme();

  return (
    <button onClick={toggleTheme}>
      Current Theme: {theme}
    </button>
  );
}
2. 类组件中使用 Context(两种方式)
TypeScript 复制代码
// 方式一:static contextType
class ThemeDisplay extends React.Component {
  static contextType = ThemeContext;

  render() {
    return <div>Current Theme: {this.context}</div>;
  }
}

// 方式二:Consumer
class ThemeButton extends React.Component {
  render() {
    return (
      <ThemeContext.Consumer>
        {(theme) => (
          <button style={{ background: theme }}>
            {this.props.children}
          </button>
        )}
      </ThemeContext.Consumer>
    );
  }
}

5、常见错误示例

1. 未提供 Provider
TypeScript 复制代码
// 错误:使用默认值但期望动态更新
function BrokenComponent() {
  const theme = useContext(ThemeContext); // 默认值 'light'
  return <div>{theme}</div>; // 永远显示 'light'
}

// 正确做法:确保外层有 Provider
function App() {
  return (
    <ThemeContext.Provider value="dark">
      <BrokenComponent />
    </ThemeContext.Provider>
  );
}
2. 直接传递对象导致重复渲染
TypeScript 复制代码
// 错误写法:每次渲染创建新对象
function App() {
  return (
    <ThemeContext.Provider value={{ theme: 'dark' }}> {/* 每次渲染新对象 */}
      <Child />
    </ThemeContext.Provider>
  );
}

// 正确做法:使用 useMemo
function App() {
  const value = useMemo(() => ({ theme: 'dark' }), []);
  return (
    <ThemeContext.Provider value={value}>
      <Child />
    </ThemeContext.Provider>
  );
}

通过这些示例,可以更清晰地理解 Context.ConsumeruseContext 的具体用法与差异。实际开发中:

  • 优先使用 useContext(函数组件)

  • 类组件使用 static contextTypeConsumer

  • 复杂场景结合 useMemo + memo 优化性能

五、性能优化策略

  1. 拆分 Context

    将高频更新和低频更新的数据分离到不同 Context

    TypeScript 复制代码
    // 分开定义
    const SettingsContext = createContext();
    const UserContext = createContext();
  2. 记忆化值对象

    使用 useMemo 避免不必要的重渲染

    TypeScript 复制代码
    const contextValue = useMemo(() => ({ theme, toggleTheme }), [theme]);
  3. 使用选择器模式

    通过高阶组件实现精准订阅(类似 Redux 的 connect)

    TypeScript 复制代码
    const useTheme = () => {
      const { theme } = useContext(ThemeContext);
      return theme;
    };
  4. 避免嵌套 Provider

    保持 Provider 层级扁平化

六、常见问题解决方案

1. 默认值不生效?
  • 确保组件树中没有匹配的 Provider 时才会使用默认值

  • 总是显式提供 Provider 的 value 属性

2. 组件不更新?
  • 检查 Provider 的 value 是否总是创建新对象

  • 使用 useMemo 优化:

    TypeScript 复制代码
    const value = useMemo(() => ({ theme, toggleTheme }), [theme]);
3. 多个 Context 如何管理?
  • 使用组合 Provider:

    TypeScript 复制代码
    <UserProvider>
      <ThemeProvider>
        <App />
      </ThemeProvider>
    </UserProvider>
4. Class 组件如何使用?
  • 使用 static contextTypeContext.Consumer

    TypeScript 复制代码
    class MyClass extends React.Component {
      static contextType = ThemeContext;
      
      render() {
        const { theme } = this.context;
        return <div>{theme}</div>;
      }
    }

七、Context vs Redux

特性 Context API Redux
学习成本 较高
调试工具 无内置 Redux DevTools
中间件支持 不支持 支持
适用场景 中小应用 大型复杂应用
性能优化 需手动优化 自动优化
代码量 较少 较多

八、最佳实践

  1. 避免滥用:只在需要跨多层组件通信时使用

  2. 类型安全:配合 TypeScript 定义 context 类型

    TypeScript 复制代码
    interface ThemeContextType {
      theme: 'light' | 'dark';
      toggleTheme: () => void;
    }
  3. 文档规范:为每个 Context 添加使用说明

  4. 测试策略:使用 Mock Provider 进行单元测试

码字不易,各位大佬点点赞呗

相关推荐
木辰風4 小时前
vue These dependencies were not found
前端·javascript·vue.js
非晓为骁4 小时前
【Python】在Windows下配置Python最小环境并在React执行Python脚本
windows·python·react.js
yzzzz4 小时前
控制并发
前端·javascript·面试
前端小胡兔4 小时前
解决vue中formdata 传值为空 控制台报错SyntaxError - expected expression, got ‘<‘
前端·javascript·vue.js
best6665 小时前
JavaScript中, new类之后,是静态成员先定义,还是构造函数先执行?
javascript
fury_1236 小时前
v-model=‘xxx‘和v-model:visible=‘xxx‘有什么区别
前端·javascript·vue.js
Tiffany_Ho6 小时前
原型链与继承
前端·javascript
Au_ust6 小时前
千峰React:外部库引用
前端·javascript·react.js
IT、木易6 小时前
大白话React第十二章深入地掌握 React 的高级特性
前端·react.js·前端框架