• useReducer+createContext真的可以代替Redux吗?


    概念

    useReducer

    useReducer 是 React 提供的一个状态管理钩子,通常用于管理组件的复杂状态逻辑。它采用两个参数:reducer 函数和初始状态。Reducer 函数接受当前状态和一个操作(action),并返回一个新的状态。这有点类似于 Redux 中的 reducer 函数。使用 useReducer 可以更清晰地管理组件的状态更新逻辑,特别适用于处理多个相关状态或者需要执行复杂计算的情况。在某些场景下可以作为 useState 的替代方案。

    使用方式:

    const [state, dispatch] = useReducer(reducer, initialState) 
    
    • 1

    它返回当前的状态state,和dispatch方法。当我们需要改变状态时,调用dispatch方法:

    dispatch({type: 'increment'})  
    
    • 1

    这会触发reducer函数,返回新的状态值。

    例子:计数器

    // 定义 reducer 函数,接受当前状态和操作(action),返回新状态
    const counterReducer = (state, action) => {
      switch(action.type) {
        case 'increment': 
          return {count: state.count + 1}
        case 'decrement':
          return {count: state.count - 1}  
        default:
          return state
      }
    }
    
    // 计数器函数
    function Counter() {
    // 使用 useReducer 钩子,传入 reducer 函数和初始状态
      const [state, dispatch] = useReducer(counterReducer, {count: 0})
    
      return (
        <div>
          <button onClick={() => dispatch({type: 'increment'})}>+</button>
          <span>{state.count}</span>
          <button onClick={() => dispatch({type: 'decrement'})}>-</button>
        </div>  
      )
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25

    这样通过useReducer可以抽离状态管理逻辑,使组件更加清晰。

    useContext

    useContext 是 React 提供的一个钩子,用于在函数组件中访问上下文(context)中的数据。上下文是一种跨组件树传递数据的方式,它可以避免通过中间组件的 props 一层层传递状态的麻烦。,特别适用于共享全局状态或应用程序范围的配置信息。
    这里举个全局主题色的例子

    import React, { createContext, useContext, useState } from 'react';
    
    // 创建一个上下文对象
    const ThemeContext = createContext();
    
    function App() {
      const [theme, setTheme] = useState('light');
    
      return (
        // 使用 ThemeContext.Provider 提供数据
        <ThemeContext.Provider value={theme}>
          <div>
            <Header />
            <Main />
          </div>
          <button onClick={() => setTheme(theme === 'light' ? 'dark' : 'light')}>
            Toggle Theme
          </button>
        </ThemeContext.Provider>
      );
    }
    
    function Header() {
      // 使用 useContext 钩子来访问上下文中的数据
      const theme = useContext(ThemeContext);
    
      return (
        <header style={{ backgroundColor: theme === 'dark' ? 'black' : 'white' }}>
          Header Content
        </header>
      );
    }
    
    function Main() {
      // 使用 useContext 钩子来访问上下文中的数据
      const theme = useContext(ThemeContext);
    
      return (
        <main style={{ color: theme === 'dark' ? 'white' : 'black' }}>
          Main Content
        </main>
      );
    }
    
    export default App;
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39
    • 40
    • 41
    • 42
    • 43
    • 44
    • 45

    在这个示例中,创建了一个 ThemeContext 上下文对象,然后在 App 组件中使用 ThemeContext.Provider 提供了一个名为 theme 的数据。这个数据代表当前的主题。

    在 Header 和 Main 组件中,我们使用 useContext 钩子来访问 ThemeContext 上下文中的 theme 数据。这使得这两个组件可以获取到 theme 数据,无需通过 props 一级一级传递,而且当主题变化时,这两个组件会自动更新。

    最后,App 组件中的 “Toggle Theme” 按钮允许我们在浅色主题和深色主题之间切换,因为 theme 状态是在 App 组件中管理的,而通过上下文传递给了 Header 和 Main 组件。

    useReducer+createContext例子

    使用 React 的 useReducerContext 是一种强大的方式来管理应用的全局状态,特别是当需要在多个组件之间共享状态时。避免了组件间层层传递的props,有更清晰的状态管理,useReducer 抽取状态逻辑,状态改变更可预测。context 将状态提取到组件树外,与业务逻辑解耦。
    下面是一个基本示例,展示如何使用这两个特性来扩展你的应用。

    首先,创建一个全局的状态管理器和上下文。这个上下文将包含状态以及状态更新的函数:

    import React, { createContext, useReducer, useContext } from 'react';
    
    // 创建一个初始状态
    const initialState = {
      count: 0,
    };
    
    // 创建一个 reducer 函数来处理状态更新
    function reducer(state, action) {
      switch (action.type) {
        case 'INCREMENT':
          return { count: state.count + 1 };
        case 'DECREMENT':
          return { count: state.count - 1 };
        default:
          return state;
      }
    }
    
    // 创建上下文
    const AppContext = createContext();
    
    // 创建上下文的 Provider 组件
    export function AppProvider({ children }) {
      const [state, dispatch] = useReducer(reducer, initialState);
    
      return (
        <AppContext.Provider value={{ state, dispatch }}>
          {children}
        </AppContext.Provider>
      );
    }
    
    // 自定义 hook 用于访问上下文
    export function useAppContext() {
      return useContext(AppContext);
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37

    在上面的代码中,创建了一个状态管理器,包含了一个状态对象和一个 reducer 函数,以处理状态的更新。然后,使用 createContext 创建了一个上下文,并创建了一个名为 AppProvider 的组件,它将状态和 dispatch 函数提供给上下文。最后,创建了一个自定义 hook useAppContext,用于访问上下文。

    接下来,就可以在应用中使用这个上下文和状态管理器。这是一个示例组件,演示如何使用全局状态:

    import React from 'react';
    import { useAppContext } from './AppContext';
    
    function Counter() {
      const { state, dispatch } = useAppContext();
    
      return (
        <div>
          <p>Count: {state.count}</p>
          <button onClick={() => dispatch({ type: 'INCREMENT' })}>Increment</button>
          <button onClick={() => dispatch({ type: 'DECREMENT' })}>Decrement</button>
        </div>
      );
    }
    
    function App() {
      return (
        <div>
          <h1>My App</h1>
          <Counter />
        </div>
      );
    }
    
    export default App;
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25

    在这个示例中,导入了 useAppContext 钩子,然后在 Counter 组件中使用它来获取全局状态和 dispatch 函数。Counter 组件能够访问全局状态并触发状态的更新,这将反映在整个应用中。

    最后,在应用的根组件中使用 AppProvider,以使全局状态在整个应用中可用:

    import React from 'react';
    import { AppProvider } from './AppContext';
    import App from './App';
    
    function Root() {
      return (
        <AppProvider>
          <App />
        </AppProvider>
      );
    }
    
    export default Root;
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13

    总结

    useReducer + createContext 确实可以在一些场景下替代 Redux,但并不能真正的取代,只是某些场景可以不用redux。在选择使用哪个的时候先根据自己习惯和项目需要。
    例如:

    1. 状态管理复杂度

    如果状态逻辑非常复杂,多组件共享、包含大量业务逻辑,Redux 的集中式状态管理仍很有必要。useReducer + createContext 适合中小规模状态管理。

    1. 中间件需求

    Redux 的强大中间件(如 Redux Thunk、Saga)可以解决更多场景,useReducer 的中间件支持较弱。

    1. 调试体验

    Redux Devtools 提供了更好的调试体验。useReducer 需要自行实现。

    1. TypeScript 集成

    Redux 对 TypeScript 支持更友好。

    1. 项目规模

    在大项目中,Redux 的结构性和可预测性做得更好。

    所以,是使用 Redux还是HOOKS,还是需要看团队规模、项目复杂度等具体情况。但在一些中小型项目中,useReducer + createContext 可以作为一个简单有效的状态管理方案。

  • 相关阅读:
    Protobuf用法和实际操作总结
    【AWS】在EC2上创建root用户,并使用root用户登录
    数字IC设计 - 逻辑综合简介与Design Compiler使用(GUI方式)
    [附源码]java毕业设计基于篮球云网站
    【计算机毕设之基于Java的贫困生资助管理系统-哔哩哔哩】 https://b23.tv/LrumkKI
    Vue项目实战
    springboot自定义Json序列化返回,实现自动转换字典值
    DDD战略设计--如何设计聚合(含示例代码)
    为什么网安人才缺口那么大,就业率却上不去?
    手写模拟SpringBoot组件核心原理
  • 原文地址:https://blog.csdn.net/study_way/article/details/133948465