データフロー

Reduxのアーキテクチャは、厳格な一方向のデータフロー を中心に設計されています。

アプリケーション内のすべてのデータが、同じライフサイクルパターンをたどるということです。これによりアプリのロジックがより予測しやすく、理解しやすくなります。また、データの正規化が促されます。そのためお互いにつながりが無い、同じデータの複製をいくつも作らなくてすみます。

まだピンとこないなら、モチベーションFluxが役立つ場合(The Case for Flux)を読んでください。一方向のデータフローを支持する、説得力のある主張です。Reduxは正確にはFluxではないのですが、主な利点は同じです。

どんなReduxアプリでも、データのライフサイクルは次の4ステップをたどります:

  1. store.dispatch(action)を呼び出す。

    Action起きたこと を表す単なるオブジェクトです。例えば:

     { type: 'LIKE_ARTICLE', articleId: 42 }
     { type: 'FETCH_USER_SUCCESS', response: { id: 3, name: 'Mary' } }
     { type: 'ADD_TODO', text: 'Reduxのドキュメントを読む。' }
    

    Actionを、とても簡潔なニュースの断片だと考えてください。“メアリーは記事42にいいねした。” とか “‘Reduxのドキュメントを読む。’がTodoリストに追加された。” など。

    アプリのどこからでもstore.dispatch(action)を呼び出せます。コンポーネント(構成要素)やXHRコールバック、あらかじめ決められた間隔でも呼び出せます。

  2. Redux Storeが、与えられたReducer関数を呼び出す。

    Storeは、2つの引数をReducerに渡します。現在の状態ツリーとActionです。例えばTodoアプリで、ルート(大元の)Reducerは次のような状態とActionを受け取るでしょう:

     // 現在のアプリケーション状態(Todoのリストと、選択されたフィルター)
     let previousState = {
       visibleTodoFilter: 'SHOW_ALL',
       todos: [
         {
           text: 'ドキュメントを読む。',
           complete: false
         }
       ]
     }
    
     // 実行されたAction(Todoの追加)
     let action = {
       type: 'ADD_TODO',
       text: '流れを理解する'
     }
    
     // Reducerは次のアプリケーション状態を返す
     let nextState = todoApp(previousState, action)
    

    Reducerは純粋関数であることに注意してください。次の状態を 計算する だけです。完全に予測可能であるべきです。つまり同じ入力には、何度やっても同じ出力を返すのです。副作用は、どんなものでも行うべきではありません。例えば、API呼び出しやルート遷移など。これらは、ActionをDispatch(送信)する前に行うべきです。

  3. ルートReducerは、複数のReducerの結果を1つの状態ツリーにまとめてよい。

    ルートReducerをどのように構成するかは、すべてあなた次第です。ReduxはcombineReducers()というヘルパー関数を提供しています。ルートReducerを複数の関数へ“分割する”のに役立ちます。それぞれの関数は、 状態ツリーの一部を処理します。

    combineReducers()がどう機能するか示します。ここでは2つのReducerがあります。1つはTodoリストのため、もう1つは今選択されているフィルター設定のためです:

     function todos(state = [], action) {
       // 計算は省略...
       return nextState
     }
    
     function visibleTodoFilter(state = 'SHOW_ALL', action) {
       // 計算は省略...
       return nextState
     }
    
     let todoApp = combineReducers({
       todos,
       visibleTodoFilter
     })
    

    Actionを発行すると、combineReducersによって返されたtodoAppは両方のReducerを呼び出します:

     let nextTodos = todos(state.todos, action)
     let nextVisibleTodoFilter = visibleTodoFilter(state.visibleTodoFilter, action)
    

    そして両方の結果を、1つの状態ツリーにまとめます:

     return {
       todos: nextTodos,
       visibleTodoFilter: nextVisibleTodoFilter
     }
    

    combineReducers()は手軽なヘルパー関数ですが、使わなくても構いません。ルートReducerの書き方は、あなた次第です!

  4. ReduxはルートReducerによって返された、完全な状態ツリーを保存します。

    上記で、新しいツリーがアプリの次の状態となりました!store.subscribe(listener)で登録されたすべてのリスナーは、このとき呼び出されます。リスナーはstore.getState()で現在の状態を得ることもできます。

    そして、UIの更新が可能となりました。現在の新しい状態を反映するためです。React Reduxのようなバインディング(連携プログラム)を使っているなら、このときにcomponent.setState(newState)が呼び出されます。

次のステップ

これで、Reduxがどのように機能するか分かりました。次はReactアプリにつなげましょう

上級ユーザーへの注意

基本的なコンセプトをよく理解していて、以前にこのチュートリアルを終えた方へ。上級チュートリアル非同期なフローを忘れずに確認してください。Reducerに届く前に、ミドルウェアが非同期なActionをどう変換するか学べます。

results matching ""

    powered by

    No results matching ""