ReduxToolkitとcreateContext,useReducerを使ってProviderを作成しグローバルにstateの値を管理する

# はじめに
reactを使う中でStateの管理にProviderを作る事が多いため、忘れないようにメモ。
ReactとTypescriptで書いています。初心者のため、間違っているところもあるかもしれません。

# 目次
<!-- タイトルとアンカー名を編集 -->
1. [インストール](#インストール)
1. [createSliceの作成](#createSliceの作成)
1. [ContextとProviderの作成](#ContextとProviderの作成)
1. [使い方](#使い方)

<!-- 各チャプター -->
<a id="#インストール"></a>
# インストール

```javascript:ターミナル
$ yarn add @reduxjs/toolkit react-redux
$ yarn add -D @types/react-redux
```

<a id="#createSliceの作成"></a>
# createSliceの作成
```typescript:provider.tsx
import React,{createContext,useReducer} from 'react';
import { createSlice, PayloadAction } from '@reduxjs/toolkit';

//Stateのタイプを設定
export type KakeiboState = {
    detailPlan:Array<number>;
    sumDetailPlan:number;
    resultPlan:Array<number>;
    sumResultPlan:number;
}

//Stateの初期値を設定
const initialState:KakeiboState = {
    detailPlan :[...Array(5)].fill(0),
    sumDetailPlan :0,
    resultPlan:[...Array(5)].fill(0),
    sumResultPlan:0,
}

// createSliceでreducerとactionを同時に定義
const kakeiboSlice = createSlice({
    name: 'kakeibo',
    initialState,
    reducers: {
        setDetailPlan: (state, action: PayloadAction<Array<number>>) => {
            return{ 
          ...state,
          detailPlan: action.payload,
            }
        },
        setSumDetailPlan: (state, action: PayloadAction<number>) => {
            return{ 
          ...state,
          sumDetailPlan: action.payload,
            }
        },
        setResultPlan:(state,action:PayloadAction<Array<number>>) => {
            return{
                ...state,
                resultPlan:action.payload
            }
        },
        setSumResultPlan:(state,action:PayloadAction<number>) => { 
            return{
                ...state,
                sumResultPlan:action.payload
            }
        },
        setInitialState:() => ({
            ...initialState,
        })    
    },
})

//actionとしてエクスポートする
export const {
    setDetailPlan,
    setSumDetailPlan,
    setResultPlan,
    setSumResultPlan,
    setInitialState
} = kakeiboSlice.actions;
```

<a id="#ContextとProviderの作成"></a>
# ContextとProviderの作成
```typescript:provider.tsx

//Providerに使う型の設定
type KakeiboProviderValue = {
    kakeiboInfo:KakeiboState;
    kakeiboDispatch:React.Dispatch<PayloadAction<
        |number
        |Array<number>
        >
    >;
};

//コンテクストの作成
export const KakeiboContext = createContext({} as KakeiboProviderValue);

type KakeiboProviderProps = {
    children:React.ReactNode;
};

//useReducerを使ってProviderの作成
const KakeiboProvider:React.FC<KakeiboProviderProps> = (props:KakeiboProviderProps) => {
    const [kakeiboInfo,kakeiboDispatch] = useReducer(
        kakeiboSlice.reducer,initialState);

    return(
        <KakeiboContext.Provider value={{kakeiboInfo,kakeiboDispatch}}>
            {props.children}
        </KakeiboContext.Provider>
    );
};

export default KakeiboProvider
```

<a id="#使い方"></a>
# 使い方
##
・Providerを使用したいファイルをProviderで挟みます。間にいくつ挟んでも大丈夫です。


```typescript:App.tsx

import React from 'react';
import './App.css';
import Kakeibo from './kakeibo/Component/main';
import KakeiboProvider from '../src/kakeibo/Container/Provider/provider';

const App:React.FC = () => {
  return (
    <KakeiboProvider>
        <Kakeibo />
    </KakeiboProvider>
  );
}

export default App;


```

####　インポート文

```typescript:Kakeibo.tsx
//useContextとProviderで作成したKakeiboContextをインポートします。
//stateの値を変更したい処置がある場合は、reducerに書いたものからインポートします。この場合はsetSumDetailPlanです。
import React,{useContext} from 'react'
import {KakeiboContext,setSumDetailPlan} from '../Provider/provider';

```

####　使用する時
```typescript:Kakeibo.tsx
//Providerで宣言したものを使います。
const {kakeiboInfo,kakeiboDispatch} = useContext(KakeiboContext);

//Providerから値を取得する時
conosle.log(kakeiboInfo.sumDetailPlan) //現在のstateに入っているsumDetailPlanの値が返される

//Providerを使ってstateを変化させる時
kakeiboDispatch(setSumDetailPlan(5)) //state中のsumDetailPlanに「5」が設定される

```