【TypeScript×React】useReducerとuseContextを使ってログイン状態を管理する

React

SPAを制作しているときに、Reactの状態管理でログイン状態かログアウト状態かを取得したかったため、useReducertとuseContextで実装しました。

方針

  • ログイン状態を判断するstateをグローバルで管理する
  • そのstateには、ログイン状態であればユーザーのidを挿入し、ログアウト状態であればnullを挿入する

Reducerを作成する(UserAuthReducer.ts)

Reducer用のファイルを作成し、下記コードを作成しました。

export type UserAuthState = {
  id: string | null
};
  
export type UserAuthAction = {
  type: 'setId'
  payload: string
} | {
  type: 'removeId'
};

export const userAuthReducer = (state: UserAuthState, action: UserAuthAction): UserAuthState => {
  switch (action.type) {
    case 'setId':
      return {
        ...state,
        id: action.payload
      };
    case 'removeId':
      return {
        ...state,
        id: null
      };            
    default:
      return {
        state
      };
  }
}
 
export const initialState: UserAuthState = {id: null};
  • Reducerのdispatchのタイプが ‘SetId’ であれば、stateのidに dispatchのpayloadに渡すstring(id)を挿入
  • Reducerのdispatchのタイプが ‘removeId’ であれば、stateのidに dispatchのpayloadに渡すnullを挿入
  • initialStateは、stateのidの初期値を指す

Contextを作成する(UserAuthContext.ts)

私はContext用のファイルを作成しましたが、親コンポーネントのファイルに直接書く方もいるようですので、自由です。

import React, { createContext } from 'react';
import { UserAuthState, UserAuthAction } from './reducers/UserAuthReducer';

export const UserAuthContext = createContext({} as {
  state: UserAuthState;
  dispatch: React.Dispatch<UserAuthAction>;
});

親コンポーネントにProviderを設置(app.tsx)

stateを適用したいコンポーネントたちをContext.Providerで囲みます。

// React
import React, { useReducer } from 'react';
import ReactDOM from 'react-dom';

// ContextProvider
import { UserAuthReducer, initialState } from './reducers/UserAuthReducer';
import { UserAuthContext } from './UserAuthContext';

// Components
import Search from './Search';
import Top from './Top';
import Login from './Login';

const App: React.FC = () => {
  const [state, dispatch] = useReducer(UserAuthReducer, initialState)
  return (
    <UserAuthContext.Provider value={{ state, dispatch }}>
      <div id="global-container">
        <Login />
        <Top />
        <Search />
      </div>
    </UserAuthContext.Provider>
  )
}
 
if (document.getElementById('app')) {
   ReactDOM.render(<App />, document.getElementById('app'));
}

ログイン時にstateを更新する処理を作成(Login.tsx)

以下をログイン成功時の処理と一緒に行えばOK。

import React from 'react';
import { UserAuthContext } from './UserAuthContext';

export const Login: React.FC = () => {
  const {  dispatch } = React.useContext(UserAuthContext)

  // API等を実行し、user idを取得
    dispatch({
      type: 'setId',
      payload: res.data.user.id, 
    });
  // ...

  return (
    <div>
      {/* ... */}
    </div>
  )
}

ログアウト時はこんな感じ。

import React from 'react';
import { UserAuthContext } from './UserAuthContext';

export const Login: React.FC = () => {
  const { state, dispatch } = React.useContext(UserAuthContext)
  const logout = {
    console.log(`ログアウト: ${state.id}`) // stateの値もこうやって取れる
    dispatch({
      type: 'removeId'
    });
    // その他処理
  }

  return (
    <div>
      {/* ... */}
    </div>
  )
}
  • 最初のReducerで設定した動作を行ってくれます。
  • typeが ‘setId’ であれば、payloadの内容を、stateのidに挿入します。
  • typeが ‘removeId’ であれば、stateのidにnullを挿入します。

以上です。少しでも参考になれば幸いです。

タイトルとURLをコピーしました