私の 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: true
てapp
、高レベルの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 つのアクションをさらに作成することですstartLoading
。stopLoading
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 つのアクションを呼び出すのは非常に無駄に見えます。
これはよくある問題だと思いますが、実用的で「実生活」の提案は見つかりませんでした。この問題に対する他のアプローチや、与えられた提案についての考えを聞かせていただければ幸いです。