Help us understand the problem. What is going on with this article?

Reduxは諦めてhooksのuseContextでステート管理してみる(TypeScript使います)

Reactを実装しはじめて、いよいよステートが色々なところに散らばってわけ分からなくなってきたので、Reduxを導入しようとしたら上手くいきませんでした。

そのため一旦Reduxは諦めてhooks(userReducer、useContext)を使うことにしたらやりたいことはできたし、とても簡単でしたので備忘録的に残しておきます。

useContext導入以前

sample1.tsx
export const Sample = () => {
  const [id, setId] = useState('');

  const eventHandler: (id: string) => void = id => {
    setState(id);
  };

return (
    <Container>
      <LeftContainer eventHandler={eventHandler} />
      <RightContainer id={id} />
    </Container>
  );
}

このような形でstateの中身やstateを変える関数を子要素に渡して、その子要素がさらに孫要素に渡して、、、(以下無限)みたいなことをしてました。いわゆるprop drillingっていうやつですね。

useContext導入後

useReducerも一緒に使って、親要素に全て集約し、その子孫のコンポーネントであればどこでも呼び出せるようにします。

reducer.ts
export type StateType = {
  id: string;
};

export type ActionType = {
  type: string;
  id: string;
};

export const myReducer = (state: StateType, action: ActionType) => {
  switch (action.type) {
    case 'setId':
      return { ...state, id: action.id };
    default:
      return state;
  }
};

親要素:

Parent.tsx
import React, { useState, createContext, useReducer } from 'react';
import { Child } from './Child';
import { myReducer, StateType, ActionType } from './reducer';

// contextの型を宣言
// stateはParentコンポーネントのステート
// dispatchはステートを変える関数(正確にはどの処理を行うか振り分けるためのもの)
type ContextType = {
  state: StateType;
  dispatch: React.Dispatch<ActionType>;
};

// ステートの初期値を宣言
const initialState = { id: '' };

// コンテキストを作成する
export const ParentContext = createContext({} as ContextType);

const Parent = () => {
// useReducerを使ってstateとdispatchを宣言。reducerは上記で作成済みのものを使う
  const [state, dispatch] = useReducer(myReducer, initialState);

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

export default Parent;

retunで返しているJSX要素を見ていただけると分かりますが、Childコンポーネントにはpropsとして何も渡していません。

Child.tsx
import React, { useContext } from 'react'
import { ParentContext } from '../Parent';

const Child = () => {
// ここではstateとdispatch両方受け取っているが、必要な方だけ受け取ることも可能
  const { state, dispatch } = useContext(ParentContext);

  return(
    <div
       id="newId"
       onClick={(e) =>
          dispatch({
              type: 'setId', // reducerで指定したtypeを使う
              id: e.target.id,
           })
        }
    >
      {state}
    </div>
  );
}

親要素(先祖要素)から受け取ったcontextを使うことで、propsの受け渡しをせずに、子孫要素で作成したcontextを使うことができるようになりました!
ちなみにuseContextを使っても、propsは普通に子要素に受けわたすことができるので使い分けも可能です。

将来的に複雑なことをするかもと思い、Reduxの導入をチャレンジしたのですが、結果的には今はやりたいことがこれだけで十分でした。

学習コストがほぼ0なのと、Reduxのステートの管理とは干渉しないっぽいのでとりあえず導入してみるのがおすすめです。

ちなみに

Reduxの導入を諦めた理由は、バックエンドにGraphQLを使っていて、そのクライアントにapollo-clientを使用しているのですが、それがどうも干渉してる感じでした。(ここがわからず2日くらい上手くいかないと悩んでた)

apollo-clientのバージョン1ではReduxと併用できて、バージョン2でできなくなったものの、apollo-cache-reduxというライブラリを使えば可能ということだったのですが、apollo-cache-reduxは公式でもうメンテナンスしないみたいになってたので、結局Reduxは使えず。。。

Apollo Client自体でステートの管理もできそうな感じしてるのですが、とりあえず今回はuseContext使おうと思いました。

参考資料

Reduxから Context API with Hooks へ
【react hooks】useContextを使ってみた
React createContext issue in Typescript?
reduxでgraphqlを使う
apollo-cache-redux(github)

Why not register and get more from Qiita?
  1. We will deliver articles that match you
    By following users and tags, you can catch up information on technical fields that you are interested in as a whole
  2. you can read useful information later efficiently
    By "stocking" the articles you like, you can search right away
Comments
No comments
Sign up for free and join this conversation.
If you already have a Qiita account
Why do not you register as a user and use Qiita more conveniently?
You need to log in to use this function. Qiita can be used more conveniently after logging in.
You seem to be reading articles frequently this month. Qiita can be used more conveniently after logging in.
  1. We will deliver articles that match you
    By following users and tags, you can catch up information on technical fields that you are interested in as a whole
  2. you can read useful information later efficiently
    By "stocking" the articles you like, you can search right away
ユーザーは見つかりませんでした