# Context + useReducer 实现全局状态管理

URL: https://caijiao.org/react/chapter9/context-reducer
Source: docs/react/chapter9/context-reducer.md
Description: 结合 Context 和 useReducer 可以实现全局状态管理，适用于多个组件共享状态的场景。useReducer 提供了一种集中式的状态更新方式，而 Context 使得这些状态可以在组件树中进行共享。这个组合可以帮助我们避免 prop drilling（层层传递 props）的问题，简化状态管理。

## 什么是全局状态管理？

在 React 应用中，当多个组件需要共享相同的状态时，可以使用全局状态管理来避免重复的状态传递或“prop drilling”。通过将状态提升到应用的更高层级，或者使用状态管理库（如 Redux），可以让不同组件访问和更新同一份状态。

`Context` 和 `useReducer` 是 React 中提供的两种工具，它们结合使用可以轻松实现一个简单的全局状态管理系统。`useReducer` 管理状态的变化逻辑，而 `Context` 提供了一个共享状态的机制，使得我们可以避免在多个组件之间传递 props。

## 如何使用 Context + useReducer 实现全局状态管理？

### 步骤 1：创建 Reducer 和 初始状态

首先，我们需要定义一个 `reducer` 函数和初始状态，这部分与普通的 `useReducer` 使用方式相同。

```javascript
// reducer.js
export const initialState = { count: 0 };

export function reducer(state, action) {
  switch (action.type) {
    case 'increment':
      return { count: state.count + 1 };
    case 'decrement':
      return { count: state.count - 1 };
    default:
      return state;
  }
}
````

### 步骤 2：创建 Context 和 Provider

接下来，创建一个 Context 来共享全局状态，并通过 `useReducer` 提供状态和 `dispatch` 函数。

```javascript
// GlobalStateContext.js
import React, { createContext, useContext, useReducer } from 'react';
import { reducer, initialState } from './reducer';

// 创建 Context
const GlobalStateContext = createContext();

// 创建 Provider 组件
export function GlobalStateProvider({ children }) {
  const [state, dispatch] = useReducer(reducer, initialState);

  return (
    
  );
}

// 自定义 Hook，用于访问全局状态
export function useGlobalState() {
  const context = useContext(GlobalStateContext);
  if (!context) {
    throw new Error('useGlobalState must be used within a GlobalStateProvider');
  }
  return context;
}
```

### 步骤 3：在根组件中包裹 Provider

在应用的根组件中使用 `GlobalStateProvider`，使得应用中的任何子组件都可以访问到全局状态。

```javascript
// App.js
import React from 'react';
import { GlobalStateProvider } from './GlobalStateContext';
import Counter from './Counter';

function App() {
  return (
    
  );
}

export default App;
```

### 步骤 4：使用全局状态

现在，任何子组件都可以通过 `useGlobalState` 钩子来访问和更新全局状态。下面是一个使用全局状态的示例组件。

```javascript
// Counter.js
import React from 'react';
import { useGlobalState } from './GlobalStateContext';

function Counter() {
  const { state, dispatch } = useGlobalState();

  return (
    <div>
      <p>Count: {state.count}</p>
      <button onClick={() => dispatch({ type: 'increment' })}>Increment</button>
      <button onClick={() => dispatch({ type: 'decrement' })}>Decrement</button>
    </div>
  );
}

export default Counter;
```

### 总结

* **`Context`**：提供了一个共享状态的机制，让我们能够在组件树中的不同位置访问同一个状态。
* **`useReducer`**：管理了状态的变化逻辑，允许我们以集中式的方式处理复杂的状态更新。
* **组合使用**：通过将 `useReducer` 与 `Context` 结合，能够实现类似于 Redux 的全局状态管理，同时避免了 prop drilling 和冗余的状态传递。

这种方式适用于中小型应用，具有较简单的状态需求。当应用复杂度增加时，可能需要引入更专业的状态管理库（如 Redux 或 Zustand）。
