2015-12-23 51 views
5

我有一個減速的樹,看起來像這樣:減少與終極版combineReducers的整個子樹

module.exports = combineReducers({ 
    routing: routeReducer, 
    app: combineReducers({ 
     setup: combineReducers({ 
      sets, 
      boosters 
     }), 
     servers: combineReducers({ 
      servers 
     }) 
    }) 
}); 

現在setup鍵認爲,需要進行重置一次,我們已經提交了它的形式。然而,我無法訪問整個setup樹,因爲使用combineReducers意味着reducer只處理樹的葉節點處的數據(在這種情況下爲setsboosters)。

我首先想到的是使減少這樣整個安裝樹的功能:

function setup(state, action){ 
    //If there's an action that affects this whole tree, handle it 
    switch(action.type){ 
     case "FORM_SUBMIT": //DO STUFF 
     break; 
    } 

    //Otherwise just let the reducers care about their own data 
    return combineReducers({ 
       sets, 
       boosters 
    })(state); 
} 

但是,這並不工作,也打亂了我的第一個代碼示例的很好的樹結構。

有沒有更好的解決方案,這與redux?

回答

7

combineReducers是一個不錯的模式,因爲它傾向於強制這樣一個想法,即減速器應該被限制到商店的非重疊子集,與商店本身的結構分離。它認爲你應該減少葉子,而不是分支,並且它處理分支的減少。

也就是說,使用替代模式可能有很好的理由。正如我在稍微提到related question中所提到的那樣,您可以選擇不使用純粹使用combineReducers並根據需要分解縮減器。

在你的情況,你可以裝飾你的內心combineReducers

module.exports = combineReducers({ 
    routing: routeReducer, 
    app: combineReducers({ 
     setup: setupReducer(
      combineReducers({ 
       sets, 
       boosters 
      }) 
     ), 
     servers: combineReducers({ 
      servers 
     }) 
    }) 
}); 

這裏,setupReducerhigher-order function。這可能是棘手的推理,但這裏是我如何處理它:

  • 我們知道setupReducer需要減速機作爲參數,因爲我們傳遞的combineReducers它的結果。
  • 我們知道由combineReducers返回的減速器的簽名是(state, action) => state
  • 我們也知道setupReducer必須返回一個reducer,它也是簽名(state, action) => state的函數。

換句話說,它需要一個reducer,並返回一個reducer:((state, action) => state) => ((state, action) => state)。因此,它可能看起來像:

function setupReducer(subReducer) { 
    return (state, action) => { 
     //If there's an action that affects this whole tree, handle it 
     switch(action.type){ 
      case "FORM_SUBMIT": 
       // ... create newState 
       return newState; 
      default: 
       return subReducer(state, action); 
     } 
    } 
} 

我一直在你的邏輯流程上面,但作爲謹慎一點,你可能要無條件呼叫subReducer,然後修改它的輸出。否則,你必須確保你的分支不被稱爲總是產生相同形狀的物體,這看起來像是一個潛在的耦合點。

+0

的確!當我第一次調用subReducer然後根據動作操縱它時,它完美運行。好的解決方案 – Miguel

0

@ acjay的回答是一個好主意!我只是想用舊方法reducer(state, action)而不是一個更高階的函數。所以我創建了一種以主從關係組成減速器的方法。

MasterSlave

export default function masterSlaveReducer(reducerMaster, reducerSlave) { 
    return (state, action) => { 
     const newState = reducerMaster(state, action); 
     if(newState === state){ 
      return reducerSlave(state, action); 
     } 

     return newState; 
    }; 
} 

米格爾的代碼會以這種方式然後用於:

module.exports = combineReducers({ 
    routing: routeReducer, 
    app: combineReducers({ 
     setup: masterSlaveReducer(
      setup, // setup() from Miguel's question 
      combineReducers({ 
       sets, 
       boosters 
      }) 
     ), 
     servers: combineReducers({ 
      servers 
     }) 
    }) 
});