0
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

Reactでfluxの実装をする

Posted at

はじめに

表題通り、Reactでfluxのデザインパターンを実装していきます。

成果物

題材はカウンターです。+1ボタンを押すとインクリメントされ、リセットボタンを押すとリセットされるよくあるカウンターの実装です。
スクリーンショット 2023-11-25 13.06.01.png

Hands-on

ディレクトリ構成
~/develop/react/react_flux$ tree -I node_modules 
.
├── README.md
├── package.json
├── public
│   ├── favicon.ico
│   ├── index.html
│   ├── logo192.png
│   ├── logo512.png
│   ├── manifest.json
│   └── robots.txt
├── src
│   ├── App.tsx
│   ├── Counter.tsx
│   ├── commons
│   │   ├── Store.tsx
│   │   ├── actions.ts
│   │   ├── counterReducer.ts
│   │   ├── reducer.ts
│   │   └── state.ts
│   ├── index.tsx
│   └── logo.svg
├── tsconfig.json
└── yarn.lock

4 directories, 19 files
index.tsx
import React from "react";
import ReactDOM from "react-dom/client";
import App from "./App";

const root = ReactDOM.createRoot(
  document.getElementById("root") as HTMLElement
);
root.render(
  <React.StrictMode>
    <App />
  </React.StrictMode>
);
src/App.tsx
import React, { useReducer } from "react";
import { reducer } from "./commons/reducer";
import { initialState } from "./commons/state";
import Store, { StoreContext } from "./commons/Store";
import Counter from "./Counter";

function App() {
  // state は現在の状態を表す変数、dispatch は状態を変更するための関数
  const [state, dispatch] = useReducer(reducer, initialState);
  // StoreContext は、state と dispatch を保持するコンテキスト
  const context: StoreContext = {
    state,
    dispatch,
  };

  return (
    <Store.Provider value={context}>
      <Counter />
    </Store.Provider>
  );
}

export default App;
src/Counter.tsx
import React, { useContext } from "react";

import Store from "./commons/Store";
import { COUNTER_INCREMENT, COUNTER_RESET } from "./commons/actions";

export default function Counter() {
  // useContext を使って StoreContext から state と dispatch を取得
  const context = useContext(Store);
  const { state, dispatch } = context;

  const increment = () => dispatch({ type: COUNTER_INCREMENT });

  const reset = () => dispatch({ type: COUNTER_RESET });

  return (
    <div>
      <h1>現在のカウンター値:{state.counter.count}</h1>
      <button onClick={increment}>+1</button>
      <button onClick={reset}>リセット</button>
    </div>
  );
}

src/commons/actions.ts
export const COUNTER_INCREMENT = "INCREMENT";
export const COUNTER_RESET = "RESET";

type CounterActionTypes = typeof COUNTER_INCREMENT | typeof COUNTER_RESET;

type ActionTypes = CounterActionTypes;

export type Action = {
  type: ActionTypes;
};
src/commons/counterReducer.ts
import type { Reducer } from "react";
import { COUNTER_INCREMENT, type Action, COUNTER_RESET } from "./actions";
import type { GlobalState } from "./state";

import { initialState } from "./state";

export const counterReducer: Reducer<GlobalState["counter"], Action> = (
  state,
  action
) => {
  switch (action.type) {
    case COUNTER_INCREMENT: {
      const count = state.count + 1;
      return {
        ...state,
        count,
      };
    }

    case COUNTER_RESET: {
      return { ...initialState.counter };
    }

    default:
      return state;
  }
};

src/commons/reducer.ts
import type { Reducer } from "react";
import type { Action } from "./actions";
import type { GlobalState } from "./state";

import { counterReducer } from "./counterReducer";

export const reducer: Reducer<GlobalState, Action> = (state, action) => {
  return {
    action,
    counter: counterReducer(state.counter, action),
  };
};

src/commons/state.ts
import type { Action } from "./actions";

export type GlobalState = {
  action: Action | null;
  counter: CounterState;
};

type CounterState = {
  count: number;
};

export const initialState: GlobalState = {
  action: null,
  counter: {
    count: 0,
  },
};

src/commons/Store.tsx
import type { GlobalState } from "./state";
import type { Action } from "./actions";

import React from "react";

export type StoreContext = {
  state: GlobalState;
  dispatch: (action: Action) => void;
};

const Store = React.createContext({} as StoreContext);

export default Store;

0
0
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
0
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?