2016-02-20 29 views
0

我的我的终极版状态树的心智模式看起来是这样的:如何编写一个带嵌套对象状态减速

{ 
    selectedDepartment: 'Chemistry', 
    purchasesByDepartment: { 
    Chemistry: { 
     purchaseOrders: { 
     ... 
     }, 
     invoices: { 
     ... 
     } 
    }, 
    Biology: { 
     purchaseOrders: { 
     ... 
     }, 
     invoices: { 
     ... 
     } 
    }, 

    ...(another department, etc) 
    } 
} 

这里是我的减速器

const purchasesByDepartment = (state = {}, action) => { 
    switch (action.type) { 
    case RECEIVE_POS: 
     return Object.assign({}, state, { 
     [action.department]: { 
      purchaseOrders: action.json 
      // but this wipes out my invoices   
     } 
     }) 
    case RECEIVE_INVOICES: 
     return Object.assign({}, state, { 
     [action.department]: {   
      invoices: action.json 
      // but this wipes out my purchaseOrders 
     } 
     }) 

    default: 
     return state 
    } 
} 

可以在每个部门看,我有一个purchaseOrders和一个发票密钥。 我正在尽我所能写我的减速器,使它不会改变我的状态,但我没有运气,因为每个动作当前擦除了另一个键。

我启动了两项操作:RECEIEVE_POS,RECEIVE_INVOICES。

当我的行动RECEIVE_POS被调度时,我可以用购买订单创建一个新的状态,但是这会抹掉我的发票。

当我的行动RECEIVE_INVOICES被调度时,我可以用发票创建一个新的状态,但是这消除了我的订单。

如何编写我的reducer以便我的订单和发票保持在我的状态下?

回答

0

对象传播计算的属性名称帮我解决这个问题

case RECEIVE_POS: 
    return { 
    ...state, 
    [action.department]: { 
     ...state[action.department], 
     purchaseOrders: action.json 
    } 
    } 
case RECEIVE_INVOICES: 
    return { 
    ...state, 
    [action.department]: { 
     ...state[action.department], 
     invoices: action.json 
    } 
    } 
2

您可以先应用更改为部门创建新状态,然后将其合并到缩减器状态中。

const purchasesByDepartment = (state = {}, action) => { 
    switch (action.type) { 
    case RECEIVE_POS: 
     let nextPOS = Object.assign({}, state[action.department] || {}, { 
     purchaseOrders: action.json 
     }); 

     return Object.assign({}, state, nextPOS); 
    default: 
     return state 
    } 
} 

个人而言,我喜欢让我的整个商店一成不变的使用immutablejs使操作这样的(和一堆其他的东西)简单:

return state.setIn([action.department, 'purchaseOrders'], action.json]); 
+0

我喜欢这个答案相结合。看起来我需要花一些时间检查ImmutableJS – Kevin

1

我使用扩运算符(表示为...arrayName ) 为了达成这个。这是es6,我用babel启用了这个功能。

Spread将数组分解为其元素,因为它比Object.assign更具人类可读性。

使用你的背景下,在我的减速器一个简单的场景,我只是去这样的:

return { 
    ...state, 
    selectedDepartment: 'Chemistry or whatever' 
} 

这将返回状态组成的阵列,加上selectedDepartment与给定值覆盖。

对于嵌入的对象,你可以把它像这样:

return { 
    ...state, 
    purchasesByDepartment: { 
     ...state.purchasesByDepartment, 
     Chemistry: { 
      ...state.purchasesByDepartment.Chemistry, 
      invoices: { 
       {your new invoices object comes here} 
      } 
     } 
    } 
} 
+0

您的回答给了我一个使用Object spread与计算属性名称结合来解决此问题的想法 – Kevin

+0

确实,它看起来不错。 – Mark