用語

ここではReduxでよく使われる用語をその型と併せて説明します。その型はFlowの表記を使って説明します。

State

type State = any

State (別名 state tree )はいろいろな意味を持ちます。通常、Redux APIでは、Storeによって管理され、getState()で返される単独の状態を意味します。 それはReduxを使ったアプリケーション全体の状態を表します。多くの場合、その状態は複雑なObjectです。

State自体はObjectやMapのようなkey-value collectionであることが多いですが、技術的には任意の型で問題ありません。それでも、Stateをシリアライズできるようにするべきです。簡単にJSONに変換できない物はStateの中に入れないようにしてください。

Action

type Action = Object

Action はStateを変更する注文を表す素のObjectです。ActionはデータをStoreに渡す唯一の方法です。つまり、UIイベントやネットワークコールバックやWebSocketのような他のソースからのデータは最終的にActionとしてdispatchする必要があります。

Actionにそれの種類を示すtypeフィールドを設定する必要があります。typeフィールドの値は定数として定義したり、他のモジュールからimportすることができます。typeフィールドの値はSymbolsより文字列の方が適しています。なぜなら、シリアライズできるからです。

typeフィールド以外のActionオブジェクトの構造は特に決まっていません。それに興味がある場合は、Flux Standard Actionが参考になると思います。

以下のAsync Actionも見ましょう。

Reducer

type Reducer<S, A> = (state: S, action: A) => S

reducer (別名 reducing function) は累算結果と値を受け取って、新しい累算結果を返す関数です。 これはコレクションの値を1つの値に畳み込むために使われます。

ReducerはReduxだけの概念ではありません。関数型プログラミングの基本的な概念です。JavaScriptのようなほとんど関数型言語でない言語でも、reduceするためのAPIを備えています。JavaScriptのそれはArray.prototype.reduce()です。

Reduxでは累算結果はStateオブジェクトです。そして、累算される値はActionです。Reducerは既存のStateとActionを受け取って新しいStateを算出します。Reducerは 純粋関数(Pure Function) である必要があります。つまり、同じ入力に対して完全に同じ出力を返す必要があります。

hot reloadingやtime travelのような素晴らしい機能を動作させるために、Reducerは副作用(side-effects)を含んでいてはいけません。

ReducerはReduxの最も重要なコンセプトです。

API呼び出しをReducerに入れないでください。

Dispatching Function

type BaseDispatch = (a: Action) => Action
type Dispatch = (a: Action | AsyncAction) => any

Dispatching Function (または、simply dispatch function )は、1つのActionもしくは1つのAsync Actionを受け取る関数です。この関数は1つのActionもStoreへdispatchしない場合と1つまたは複数のActionをStoreへdispatchする場合があります。

一般的なDispatching FunctionとStoreインスタンスのMiddlewareを通さないBase Dispatch Functionは異なります。

Base Dispatch Functionは常に同期的なActionをStoreのReducerへ送ります。そのActionとReducerと既存のStoreのStateを使って、新しいStateを算出します。このActionは素のObjectにReducer用の値をセットした物です。

MiddlewareはBase Dispatch Functionをラップします。これによって、dispatch関数はActionに加えてAsync Actionを取り扱うことが可能になります。(Dispatching Functionになる。)MiddlewareはActionとAsync Actionを次のMiddlewareに渡す前に、それらを変換したり、遅延したり、無視したり、それ以外の処理を加える場合があります。詳しい説明は以下にあります。

Action Creator

type ActionCreator<A, P extends any[] = any[]> = (...args: P) => Action | AsyncAction

Action Creator は端的に言うとActionを生成する関数です。もう一度言いますが、ActionはReducerへ送信されるデータ本体でAction CreaterはActionを生成する関数です。この2つを混同しないように注意してください。Action Creatorを実行するとActionが生成されるだけで、Actionはdispatchされません。Stateを変更したい場合は、Storeの dispatch関数を実行する必要があります。Actionを生成して、それを特定のStoreインスタンスにdispatchするAction Creatorを Bound Action Creator と呼びます。

Action Creatorが現在のStateを読み込んだり、APIを読み込んだり、RouterのTransitionのような副作用を発生させる必要がある場合は、Actionの代わりにAsync Actionを返す必要があります。

Async Action

type AsyncAction = any

Async Action はDispatching Functionに渡される値ですが、そのままではReducerで処理することができません。Async ActionはBase Dispatch Functionに渡される前に、Middlewareで1つまたは複数のActionに変換されます。Async Actionは適用するMiddlewareごとに型が異なります。たいてい、Async Actionは、Promiseやthunkのような非同期処理を実行するものです。Async ActionはReducerにそのまま渡されません。Middlewareで、それらの処理が完了した後、Actionがdispatchされます。

Middleware

type MiddlewareAPI = { dispatch: Dispatch, getState: () => State }
type Middleware = (api: MiddlewareAPI) => (next: Dispatch) => Dispatch

MiddlewareはDispatching Functionを関数合成して新しいDispatching Functionを返す高階関数(higher-order function)です。たいてい、それは Async ActionをActionに変換します。

Middlewareは関数合成(function composition)で生成されます。 これはログを出力やRoutingのような副作用の実行や非同期のAPIの呼び出しに対応するMiddlewareを合成することで、それぞれを(非同期の)Actionに変換する1つのMiddlewareにすることを可能にします。詳しくはapplyMiddleware(...middlewares)を見てください。

Store

type Store = {
  dispatch: Dispatch
  getState: () => State
  subscribe: (listener: () => void) => () => void
  replaceReducer: (reducer: Reducer) => void
}

Storeはアプリケーションのstate treeを保存するオブジェクトです。そのstate treeはReducerで構成されます。Reduxを使っているアプリケーションではStoreは1つのみ存在してるべきです。

詳しく知りたい場合はStore APIリファレンスを見てください。

Store Creator

type StoreCreator = (reducer: Reducer, preloadedState: ?State) => Store

Store CreatorはStoreを生成する関数です。Dispatching Functionのように、Base Store Creator(ReduxパッケージからexportされるcreateStore(reducer, preloadedState))とStore Enhancerで生成されるStore Creatorを区別する必要があります。

Store Enhancer

type StoreEnhancer = (next: StoreCreator) => StoreCreator

Store EnhancerはStore Creatorを関数合成して新しい改良されたStore Creatorを返す高階関数です。これはStoreとのやり取りを関数合成で変更できることがMiddlewareと似ています。

Store EnhancerはReactのhigher-order componentsとほとんど同じコンセプトです。だから、“component enhancers”と呼ばれることもあります。

Storeは(何らかのクラスの)インスタンスではなく関数を素のObjectにまとめたものなので、簡単に複製することができます。そして、元のStoreを変更することなく改善することができます。 composeのドキュメントにこの例があります。

たいてい、Store Enhancerを書くことはありませんが、developer toolsで提供されているStore Enhancerを使うことはあるかもしれません。それはアプリケーションに影響を与えずにtime travelを可能にします。面白いことに、Redux middlewareの実装はそれ自体がStore Enhancerです。

License

Japanese part

Attribution-NonCommercial-NoDerivatives 4.0 International (CC BY-NC-ND 4.0)

Copyright (c) 2021 38elements

Other

The MIT License (MIT)

Copyright (c) 2015-present Dan Abramov

Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the “Software”), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions:

The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.

THE SOFTWARE IS PROVIDED “AS IS”, WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.


Redux

Redux Thunk

Lit