4
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?

More than 1 year has passed since last update.

Django+Reactで学ぶプログラミング基礎(35): Reduxチュートリアル(TodoアプリのStoreをカスタマイズ)

Last updated at Posted at 2022-06-22
[前回] Django+Reactで学ぶプログラミング基礎(34): Reduxチュートリアル(TodoアプリのStore)

はじめに

前回は、TodoアプリのStoreを実装しました。
今回は、Storeのカスタマイズ方法を勉強します。

今回の内容

Todoアプリの構築

  • Redux Store
    • Store Enhancer
    • Redux Middleware

Store Enhancer

Store Enhancerとは

  • Storeをカスタマイズし、機能拡張するためのもの

    • Store作成時に、createStoreの第3引数として渡される
    • 元のdispatch/getState/subscribeを書き換えることで、Storeを拡張
  • Store Enhancerサンプル

    • src/exampleAddons/enhancers.js
      • sayHiOnDispatch
        • actionがdispatchされる度に'Hi'!をコンソールにログ出力
      • includeMeaningOfLife
        • getState()の返却値にフィールドmeaningOfLife: 42を追加

sayHiOnDispatchEnhancerを使用しStoreを作成

  • まず、sayHiOnDispatchをインポートし、createStoreの第3引数に渡す
    • preloadedState値がないため、undefinedを第2引数として渡す
src/store.js
import { createStore } from 'redux'
import rootReducer from './reducer'
import { sayHiOnDispatch } from './exampleAddons/enhancers'

const store = createStore(rootReducer, undefined, sayHiOnDispatch)

export default store
  • 次に、actionをdispatch
    • sayHiOnDispatchEnhancerは、元のstore.dispatch関数を独自のdispatchでラップ
      • store.dispatch()呼び出しは、実際sayHiOnDispatchからラッパー関数を呼び出す
        • 元の関数を呼び出してからHi!を出力
src/index.js
import store from './store'

console.log('Dispatching action')
store.dispatch({ type: 'todos/todoAdded', payload: 'Learn about actions' })
console.log('Dispatch complete')
  • VS Codeのターミナルで、アプリを起動すると、ブラウザが開かれる
C:\kanban\todo>cd redux-fundamentals-example-app
C:\kanban\todo\redux-fundamentals-example-app>npm start
  • ブラウザで、デベロッパーツールを開き(F12)、コンソールの出力を確認
    • Hi!と表示される
      image.png

includeMeaningOfLifeEnhancerを使用し、storeを作成

  • createStoreの第3引数は、1つのEnhancerのみ受け入れられる

    • 2つのEnhancerを同時に渡すには1つにマージする必要あり
  • Reduxコアのcompose関数を使用し、複数Enhancerをマージ

    • sayHiOnDispatchincludeMeaningOfLife
src/store.js
import { createStore, compose } from 'redux'
import rootReducer from './reducer'
import {
  sayHiOnDispatch,
  includeMeaningOfLife
} from './exampleAddons/enhancers'

const composedEnhancer = compose(sayHiOnDispatch, includeMeaningOfLife)

const store = createStore(rootReducer, undefined, composedEnhancer)

export default store
  • 作成したstoreを使ってみる
    • 二つのEnhancerが同時にstoreの動作を変更している
      • sayHiOnDispatchdispatchの動作を変更
        • 'Hi'!をログ出力
      • includeMeaningOfLifegetStateの動作を変更
        • フィールドmeaningOfLife: 42を追加
src/index.js
import store from './store'

store.dispatch({ type: 'todos/todoAdded', payload: 'Learn about actions' })
// log: 'Hi!'

console.log('State after dispatch: ', store.getState())
// log: {todos: [...], filters: {status, colors}, meaningOfLife: 42}
  • ブラウザで、デベロッパーツールのコンソールを確認

    • 'Hi'!がログ出力される
    • フィールドmeaningOfLife: 42が追加される
      image.png
  • Store Enhancerのまとめ

    • Storeを変更する強力な手段
      • dispatch、getState、subscribeのいずれかをオーバーライドまたは置換できる
    • Reduxアプリのstoreセットアップ時、少なくとも1つのEnhancerが含まれる

ミドルウェア(Middleware)

Middlewareとは

  • リクエストを受信するフレームワークとレスポンスを生成するフレームワークの間に配置できるコード
    • Middlewareの特徴は、チェーン構造(パイプライン)
    • 1つのプロジェクトで複数の独立したサードパーティMiddlewareを使用できる

Redux Middlewareとは

  • Reduxの拡張機能(Addon)で、actionのdispatchをカスタマイズする
  • actionをdispatchしてからreducerに到達するまで、以下拡張を実施可能
    • ロギング
    • クラッシュレポート
    • 非同期APIとの通信
    • ルーティング
  • ※ Reducerと異なり、Middlewareでは、タイムアウトやその他非同期ロジックによる副作用が発生する可能性あり

Redux Middlewareをstoreに追加

  • Redux Middlewareは、Redux組み込みのapplyMiddlewareStore Enhancer上に実装されている
  • まず、applyMiddlewareを使用し、3つのMiddlewareを追加
    • これらのMiddlewareは、actionがdispatchされると番号を出力する
src/store.js
import { createStore, applyMiddleware } from 'redux'
import rootReducer from './reducer'
import { print1, print2, print3 } from './exampleAddons/middleware'

const middlewareEnhancer = applyMiddleware(print1, print2, print3)

// Pass enhancer as the second arg, since there's no preloadedState
const store = createStore(rootReducer, middlewareEnhancer)

export default store

image.png

  • 次に、actionをdispatch
src/index.js
import store from './store'

store.dispatch({ type: 'todos/todoAdded', payload: 'Learn about actions' })
// log: '1'
// log: '2'
// log: '3'

image.png

  • ブラウザで、デベロッパーツールを開き(F12)、コンソールの出力を確認
    • 三つのMiddlewareにより、123が出力される
      image.png

Middlewareのパイプライン

  • storeのdispatchに、下記Middlewareのパイプラインが形成される

    • store.dispatch(action)を呼び出すと
      • パイプラインの最初のMiddlewareが呼び出される
        • Middlewareは、actionのtypeが処理対象か確認
          • 処理対象の場合、Middlewareはカスタムロジックを実行
          • 処理対象でない場合、actionをパイプライン内の次のMiddlewareに渡す
  • Middlewareパイプラインで、actionが渡される順番

    • 1. print1Middleware(store.dispatchと見なされる)
    • 2. print2Middleware
    • 3. print3Middleware
    • 4. 元のstore.dispatch
    • 5. store内のroot reducer
  • ※ 上記はすべて関数呼び出しで、コールスタックからreturnされる

    • よって、print1Middlewareが最初に実行され、最後に終了

おわりに

ReduxのEnhancerとMiddlewareを使用し、Storeをカスタマイズしました。
次回も続きます。お楽しみに。

[次回] Django+Reactで学ぶプログラミング基礎(36): Reduxチュートリアル(MiddlewareでStoreをカスタマイズ)
4
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
4
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?