Gatsby Theme Aoi で App State を設定する

2022-01-31

Gatsby Theme Aoi で App State を設定する

post by cieloazul310

Gatsby Theme Aoi には Gatsby サイト全体で保持されるグローバルな state である App State を設定できます。この機能も前回同様、Gatsby テーマShadowing で実装します。

App State は Redux でお馴染みの reducer (リデューサ) によって実装されています。リデューサについての基礎知識が必要になります。以下の記事を参照してください。

useReducer - フック API リファレンス
ja.reactjs.org

App State ファイルと App State Context ファイルを作成

AppState.ts

// ./src/@cieloazul310/gatsby-theme-aoi-top-layout/utils/AppState.ts
export type AppState = {
  count: number;
};

export const initialAppState: AppState = {
  count: 0,
};

export type Action = { type: 'RESET' } | { type: 'INCREMENT' } | { type: 'DECREMENT' } | { type: 'SET_VALUE'; value: number };

export default function reducer(state: AppState, action: Action): AppState {
  switch (action.type) {
    case 'INCREMENT':
      return { ...state, count: state.count + 1 };
    case 'DECREMENT':
      return { ...state, count: state.count - 1 };
    case 'SET_VALUE':
      return { ...state, count: action.value };
    case 'RESET':
      return initialAppState;
    default:
      throw new Error("Reducer don't match the action type.");
  }
}
  • AppState: App State の型定義
  • initialAppState: App State の初期値
  • Action: リデューサに通すアクションの型定義
  • reducer(default export): App State のリデューサ

AppState.ts では Gatsby サイトで使う App State の型定義、初期値、リデューサ、リデューサに渡すアクションの型定義を行います。

AppStateContext.tsx

// ./src/@cieloazul310/gatsby-theme-aoi-top-layout/utils/AppStateContext.tsx
import * as React from 'react';
import { initialAppState, AppState, Action } from './AppState';

const AppStateContext = React.createContext<{
  state: AppState;
  dispatch: React.Dispatch<Action>;
}>({
  state: initialAppState,
  dispatch: () => {
    throw new Error();
  },
});

export default AppStateContext;

/**
 * A hook returns global `AppState`.
 * @returns {Object} AppState
 */
export function useAppState() {
  const { state } = React.useContext(AppStateContext);
  return React.useMemo(() => state, [state]);
}

/**
 * A hook returns `AppState` dispatch function.
 * @returns {function} React.Dispatch<Action>
 */
export function useDispatch() {
  const { dispatch } = React.useContext(AppStateContext);
  return React.useCallback(
    (action: Action) => {
      dispatch(action);
    },
    [dispatch]
  );
}

AppStateContext.tsx が元のファイルと同じ内容なのであれば、Shadowing する必要はないのではと思われるかもしれませんが、AppStatedispatch の型の不一致を引き起こします。実はそれでも動作面では問題はないのですが、ESLint に怒られてしまうので素直に AppStateContext.tsx をコピペしましょう。

App State を使う

App State はフックを使うことで全てのページ、全てのコンポーネントから利用できます。作成した AppStateContext.tsx から useAppState フックをインポートしてください。

// ./src/pages/index.tsx
import { useAppState } from '../@cieloazul310/gatsby-theme-aoi-top-layout/utils/AppStateContext.tsx';

function IndexPage() {
  const { count } = useAppState();

  return (
    <Layout>
      <h1>App State Example</h1>
      <p>current count is {count}</p>
    </Layout>
  );
}

export default IndexPage;

App State は各ページよりも上位のコンポーネントで管理されているので、ページを移動しても値が保持されます。

App State を更新する

App State を更新したい場合は、useDispatch フックをインポートして dispatch メソッドを使用します。useDispatch も全てのページ、全てのコンポーネントで利用できます。

// ./src/pages/index.tsx
import { useAppState, useDispatch } from '../@cieloazul310/gatsby-theme-aoi-top-layout/utils/AppStateContext.tsx';

function IndexPage() {
  const { count } = useAppState();
  const dispatch = useDispatch();
  const increment = () => {
    dispatch({ type: 'INCREMENT' });
  };
  const decrement = () => {
    dispatch({ type: 'DECREMENT' });
  };
  const set_value = (value: number) => () => {
    dispatch({ type: 'SET_VALUE', value });
  }

  return (
    <Layout>
      <h1>App State Example</h1>
      <p>current count is {count}</p>
      <button onClick={increment}>
        Increment
      </button>
      <button onClick={decrement}>
        Decrement
      </button>
      <div>
        {[0, 10, 100].map((d) => (
          <button key={d.toString()} onClick={set_value(d)}>{d}</button>
        ))}
      </div>
    </Layout>
  );
}

export default IndexPage;
Gatsby Theme Aoi で App State を設定する

Date: 2022-01-31

Post by cieloazul310

Categories: Gatsby Theme Aoi

0

Gatsby Theme Aoi Blog

© 2023 @cieloazul310 All rights reserved. Built with Gatsby