【React】useReducer使ってみた

## useReducerを使った状態管理
React Hooksは、関数コンポーネントで状態やライフサイクルを扱うための素晴らしいツールを提供しています。`useReducer`はその中でも特に複雑な状態管理において強力な手段となります。この記事では、`useReducer`の基本的な使い方を解説します。

### 1. useReducerの基本

`useReducer`は、状態を管理するための関数です。通常、コンポーネント内で複雑な状態を管理する場合や、状態の更新ロジックが複雑な場合に利用されます。基本の使い方を見てみましょう。

```tsx:Reducer.tsx
import { Reducer } from "react";

interface State {
  count: number;
}

interface Action {
  type: "INCREMENT" | "DECREMENT";
}

const reducer: Reducer<State, Action> = (state, action) => {
  switch (action.type) {
    case "INCREMENT":
      return { count: state.count + 1 };
    case "DECREMENT":
      return { count: state.count - 1 };
    default:
      return state;
  }
};

export default reducer;
```
```tsx:Counter.tsx
import React, { useReducer } from "react";
import reducer from "./Reducer";

const Counter: React.FC = () => {
  const [state, dispatch] = useReducer(reducer, { count: 0 });

  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;
```

### 2. useReducerとContextを組み合わせる

`useReducer`をContextと組み合わせることで、グローバルな状態管理が可能です。これにより、複数のコンポーネントで同じ状態を参照することができます。

```tsx:Reducer.tsx
import { Reducer } from "react";

export interface State {
  count: number;
}

export interface Action {
  type: "INCREMENT" | "DECREMENT";
}

const reducer: Reducer<State, Action> = (state, action) => {
  switch (action.type) {
    case "INCREMENT":
      return { count: state.count + 1 };
    case "DECREMENT":
      return { count: state.count - 1 };
    default:
      return state;
  }
};

export default reducer;
```
```tsx:CounterProvider.tsx
import { ReactNode, createContext, useReducer } from "react";
import reducer, { Action, State } from "./Reducer";


interface CounterContextProps {
  state: State;
  dispatch: React.Dispatch<Action>;
}

export const CounterContext = createContext<CounterContextProps | undefined>(
  undefined
);

const initialState = { count: 0 };

const CounterProvider: React.FC<{ children: ReactNode }> = ({ children }) => {
  const [state, dispatch] = useReducer(reducer, initialState);

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

export default CounterProvider;
```
```tsx:CounterControls.tsx
import React, { useContext } from "react";
import { CounterContext } from "./CounterProvider";

const CounterControls: React.FC = () => {
  const { dispatch } = useContext(CounterContext)!; // 非nullアサーション演算子

  return (
    <div>
      <button onClick={() => dispatch({ type: "INCREMENT" })}>Increment</button>
      <button onClick={() => dispatch({ type: "DECREMENT" })}>Decrement</button>
    </div>
  );
};

export default CounterControls;
```
```tsx:Counter.tsx
import React, { useContext } from "react";
import { CounterContext } from "./CounterProvider";

const Counter: React.FC = () => {
  const { state, dispatch } = useContext(CounterContext)!; // 非nullアサーション演算子

  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;
```
### 3. useReducerの利点

- **複雑な状態管理**: `useReducer`は状態の複雑なロジックを分離しやすくします。これによりコンポーネントがより単純で理解しやすくなります。
  
- **グローバルな状態管理**: Contextと組み合わせることで、グローバルな状態管理が容易になります。異なる階層のコンポーネントで同じ状態を使用する場合に便利です。

- **可読性と保守性**: `useReducer`を使うことで、コンポーネントが持つロジックがより一貫していて、保守性が向上します。

### 4. まとめ

`useReducer`はReactアプリケーションにおいて、複雑な状態管理に対処するための強力なツールです。適切に利用することで、可読性や保守性を向上させつつ、柔軟で効率的なコードを記述することができます。

この記事では、初心者大学生がReact Nextを理解するためのアウトプット資料です。
間違いや意見などコメントお待ちしております！