如何使用不可变JS在Reducer上设置复杂/嵌套状态的属性?



目前我有以下对象结构定义为STORE的初始状态

{
  counter: 0,
  messages: {
    newMessages: 25,
    inbox: 100
  }
}

在这里,我使用的是不可变的JS,在我的化简器中,如果我想修改状态,我将实现如下:

function myReducer(state: Map<string, any>, action): Map<string, any> {
  switch (action.type) {
    case COUNTER_INCREMENT:
      return state.set('counter', state.get('counter') + 1);
    case INBOX_INCREMENT:
      return state.set(xxxx, yyyy + 1);
  }
  return state;
}

当修改像counter这样的简单属性时,我们可以只使用简单

state.set('counter', state.get('counter') + 1)

但是,如果我们想修改像messages.inbox这样的复杂/嵌套属性怎么办? xxxxyyyy值应该是什么?

Immutable 提供了一个setIn命令,您可以通过该命令提供嵌套路径和设置该路径的值。

从不可变文档:

const { fromJS } = require('immutable')
const nested = fromJS({ a: { b: { c: [ 3, 4, 5 ] } } })
const nested2 = nested.mergeDeep({ a: { b: { d: 6 } } })
// Map { a: Map { b: Map { c: List [ 3, 4, 5 ], d: 6 } } }
console.log(nested2.getIn([ 'a', 'b', 'd' ])) // 6
const nested3 = nested2.updateIn([ 'a', 'b', 'd' ], value => value + 1)
console.log(nested3);
// Map { a: Map { b: Map { c: List [ 3, 4, 5 ], d: 7 } } }
const nested4 = nested3.updateIn([ 'a', 'b', 'c' ], list => list.push(6))
// Map { a: Map { b: Map { c: List [ 3, 4, 5, 6 ], d: 7 } } }

没有直接为setIn提供示例,但我想语义是相似的。可以在此处找到它的文档。

如果要为 messages.inbox 设置一个新值,可以使用setIn

return state.setIn(['messages', 'inbox'], 101)

如果要根据messages.inbox的当前值为其设置新值,可以使用updateIn

return state.updateIn(['messages', 'inbox'], inbox => inbox + 1

最新更新