3

私の Redux アプリは、モジュール性のために個々のコンポーネントに分割されています。appドメインは、インジケーターの読み込みなどの一般的な UI の変更を処理する一種の共有インフラストラクチャ コンポーネントです。

app/ <- Global app  
---app_reducer.js  
---constants.js  
---actions.js
---...(react components)
users/
---users_reducer.js
---constansts.js
---actions.js
---...(react components)
products/
---products_reducer.js
---constants.js
---actions.js
---...(react components)

ルート レデューサーでは、このcombineReducers関数を使用して、ドメインに従って状態ツリーを適切に分割します。

import { combineReducers } from 'redux';
import App from './app/app_reducer'
import Users from './users/users_reducers'
import Products from './products/products_reducers'

export default combineReducers({
  App,
  Users,
  Products
})

したがって、私の状態ツリーは次のようになります。

{
   app: 
     isLoading: false,
   users:
     ['user1', 'user2', 'user3']
   products:
     ['product1', 'product2'],
     lastFetch: 1246578942621
}

では、サーバーからデータを取得する場所に非同期機能usersを追加したいと思います。これは、または promise ミドルウェアのproductsようなものを使用すると簡単です。redux-thunkしたがって、 のアクション作成者は次のusers/actions.jsようになります。

import { LOAD_USERS_REQUEST, LOAD_USERS_SUCCESS } from './actions'

// Using redux-thunk
export function LoadUsers(){
  return function(dispatch){
     dispatch({type: LOAD_USERS_REQUEST})
     fetch('myserver.com/users')
     .then(function(data){
        dispatch({type: LOAD_USERS_SUCCESS, data })
     })
  }
}

products自身も fetch と同様のことを行う可能性があることに注意してください。
現在、これらのアクションを処理し、サブツリーusersReducerにさまざまな状態の小道具を設定します。users問題は、サブツリーにも a を設定しloading: trueapp、高レベルのappコンポーネントが適切な読み込みインジケーターをレンダリングするようにしたいということです。しかし、状態ツリーの そのスライスusersReducerは得られません。

combineReducersすべてのレデューサーに状態ツリー全体を送信するカスタムを作成せずに、これを実装するエレガントな方法は何ですか? クリーンでスケーラブルなソリューションを探しています。私が検討したいくつかのアプローチは次のとおりです。

1)appReducer新しいリクエストごとに応答するようにします。これは、フェッチ用の新しいアクション タイプを作成するたびに、次のように追加する必要があることを意味しapp/app_reducer.jsます。

import * as productTypes from '../products/constants'
import * as userTypes from '../users/constants'

export default function(state = {}, action){
  switch(action.type){
    case productTypes.LOAD_USERS_REQUEST:
    case productTypes.LOAD_PRODUCTS_REQUEST:
      return({...state, isLoading: true});
    case productTypes.LOAD_USERS_SUCCESS:
    case productTypes.LOAD_PRODUCTS_SUCCESS:
      return({...state, isLoading: false})
    default:
      return(state);
  }
}

appReducerこれに関する問題は、読み込みインジケーターを必要とする新しいアクションを作成するたびに変更する必要があることです。

2) 2 番目の方法は、次のように非同期アクションから呼び出される 2 つのアクションをさらに作成することですstartLoadingstopLoading

import { LOAD_USERS_REQUEST, LOAD_USERS_SUCCESS } from './actions'
import { START_LOADING, STOP_LOADING } from '../app/actions'    

export function LoadUsers(){
  return function(dispatch){
     dispatch({type: START_LOADING})
     dispatch({type: LOAD_USERS_REQUEST})
     fetch('myserver.com/users')
     .then(function(data){
        dispatch({type: STOP_LOADING})
        dispatch({type: LOAD_USERS_SUCCESS, data })
     })
  }
}

最初の考えでは、これは良いアイデアのように思えましたが、1 つではなく 2 つのアクションを呼び出すのは非常に無駄に見えます。

これはよくある問題だと思いますが、実用的で「実生活」の提案は見つかりませんでした。この問題に対する他のアプローチや、与えられた提案についての考えを聞かせていただければ幸いです。

4

1 に答える 1

2

このトピックはRedux FAQでカバーされています。現時点では、はい、答えは「追加のカスタム レデューサー ロジックを記述する」または「getStateより多くのデータをアクションに入れるために使用する」です。

そうは言っても、現在議論されているPRがありcombineReducers、追加の議論として州全体を引き継ぐことができます. 機能のリクエスト: レデューサーがグローバル状態を参照できるようにする を参照してください。

また、Pavel Tarno のコメントに答えるにはcombineReducers:はい。はい、各ディスパッチはすべてのサブスクライバーを呼び出します。ただし、React Redux関数は、サブスクライブされたコンポーネントの再レンダリングのみを強制します。これは、から変更/更新された結果を返します。また、React のバッチ処理により、イベント サイクルで複数の連続するディスパッチが発生し、特定のコンポーネントの再レンダリングが必要になったとしても、実際の再レンダリングはおそらく 1 回だけです。(最後に、「シャドウ DOM」ではなく「仮想 DOM」です。)connect()mapStateToProps

于 2016-06-01T16:12:09.637 に答える