たるだめ

のんびりとなんか書きます

GatsbyJSにReduxを導入する

GatsbyJSにReduxを導入する一例

コードを先に見たい方

検証用リポジトリはこちらです。

インストール


yarn add gatsby-plugin-react-redux react-redux redux

コード追加

基本的に GitHub に上げているコードと同じですが、一部コメントや import など省略している部分もあります。


gatsby-config

gatsby-config に redux 用 plugin を指定します。 オプションには createStore のソースファイルを指定します。

gatsby-config.ts
const config: GatsbyConfig = {
  plugins: [
    {
      resolve: `gatsby-plugin-react-redux`,
      options: {
        pathToCreateStoreModule: './src/state/createStore',
      },
    },
  ],
};

Redux 関連

createStore は非推奨となっていますが、Gatsby のサンプルが createStore だったのでとりあえずその通りに使用しました。

推奨される@reduxjs/toolkit への置き換えは別途試そうと思います。

src/state/createStore.ts
export interface IAppState {
  count: number;
}
export const initialState: IAppState = {
  count: 0,
};

const store = () => createStore(reducer, initialState);
export default store;

countActions.ts
const increment = (count: number): ICountAction => {
  const result = {
    type: countActionTypes.INCREMENT,
    count,
  };
  return result;
};

reducer の設定も@reduxjs/toolkit を使用しない従来の Redux の実装方法です。

reducer.ts
const appReducer = (state: any, action: IAction) => {
  if (isCountAction(action)) {
    return countReducer(state, action as ICountAction);
  }

  return state;
};
export default appReducer;

本題と関係ないですが、switch 使わないとだめでしょうか・・・?

countReducer.ts
const reducer = (state = initialState, action: ICountAction) => {
  try {
    const exec: { [key in CountActionTypes]: () => IAppState } = {
      [countActionTypes.INCREMENT]: () => increment(state, action.count),
    };
    return exec[action.type]();
  } catch (error) {
    console.error(reducer.name, error);
    return state;
  }
};

const increment = (state: IAppState, count: number) => {
  return Object.assign({}, state, {
    count: state.count + count,
  });
};

コンポーネント

増分値とカウンターを表示するだけのコンポーネント。

count.tsx
interface IProps {
  count: number;
}
const Count: React.FC<IProps> = ({ count }) => {
  const { state } = useSelector(selecter);
  const dispatch = useDispatch();
  const handleIncrement: React.MouseEventHandler<HTMLButtonElement> = (_) => {
    dispatch(countActions.increment(count));
  };
  return (
    <>
      <button onClick={handleIncrement}>インクリメント + {count}</button>
      <p>{state.count}</p>
    </>
  );
};
const selecter = (state: IAppState) => {
  console.log(selecter.name, state);
  return { state };
};

export default Count;

ページ(呼び出し側)

index.tsx
const IndexPage: React.FC<PageProps> = () => {
  return (
    <>
      <Count count={2} />
    </>
  );
}

雑感

GatsbyJS のドキュメントがアッサリしすぎていて、通常の React-Redux を使用したことない自分にとっては若干すんなりいかないところもありました 😅

@reduxjs/toolkit を使用するパターンと管理する State が増えたときの対応は考えないといけないですね。

参考