通过多于动作类型约束reducer

时间:2016-06-15 10:47:56

标签: javascript redux

我在多个页面上都有复选框过滤器,并希望它们在商店的不同部分保持独立。创建非常具体的操作类型(例如TOGGLE_CHECKBOX_SEARCHPAGE_BODYTYPE)会感觉不对,因为它需要针对每个页面和每个过滤器类型的特定reducer或在一个大型reducer中进行大量检查。 所以我认为行动应该是这样的:

{
  type: 'TOGGLE_CHECKBOX',
  page: 'search',
  filterName: 'bodyType',
  payload: 'xxxl'
}

然后我可以写函数返回约束的reducer:

function constrain(constraints, reducer) {
  return function(state, action) {
    const allConstraintsPass = Object.getOwnPropertyNames(constraints)
      .every( propName => action[propName] === constraints[propName])

    if ( ! allConstraintsPass ) {
      return reducer(state, {}) // possibly never matching {type: NaN}
    }

    return reducer(state, action)
  }
}

并像这样使用它:

function someReducer(state, action) {
  state = state || {}
  switch (action.type) {
    case 'TOGGLE_CHECKBOX':
      return Object.assign({}, state, {[action.payload]: !state[action.payload]})
    default:
      return state
  }
}

const fuelOnSearchPage = constrain({filterName: 'bodyType', page: 'search'}, someReducer)

console.log(fuelOnSearchPage(undefined, {filterName: 'fuelType', page: 'search', type: 'TOGGLE_CHECKBOX', payload: 'xxl'}));
console.log(fuelOnSearchPage(undefined, {filterName: 'bodyType', page: 'search', type: 'TOGGLE_CHECKBOX', payload: 'xs'}));
console.log(fuelOnSearchPage(undefined, {filterName: 'bodyType', page: 'search', type: 'TOGGLE_CHECKBOX', payload: 'xxl'}));
console.log(fuelOnSearchPage(undefined, {filterName: 'fuelType', page: 'search', type: 'OTHER_ACTION', payload: 'xxl'}));
console.log(fuelOnSearchPage(undefined, {type: 'OTHER_ACTION'}));

我不确定这是否是惯用的redux。在这种情况下,filterName和page似乎具有类似的用途,在某些情况下,可能不清楚应该是什么类型。 对于这类问题,你有更明确的解决方案吗?

1 个答案:

答案 0 :(得分:2)

创建非常具体的操作类型并没有错,因为操作非常具体。你在你的例子中做了完全相同的事情,它看起来有点复杂并且更难测试(并且它不遵循强烈推荐的FSA标准)。我通常将我的动作类型命名为:

export const SEARCH = {
    BODYTYPE: {
        TOGGLE: 'SEARCH.BODYTYPE.TOGGLE'
    }
}

然后用作:SEARCH.BODYTYPE.TOGGLEtypes.SEARCH.BODYTYPE.TOGGLE,具体取决于您导入的方式。

您可以根据前缀创建Reducer,而不是使用约束函数,例如:

createCheckboxReducer(prefix) {
    return function(state, action) {
        switch(action.type) {
            case `${prefix}.TOGGLE`:
                //do something
                return state;
        }
    }
}

// somewhere else
createCheckboxReducer('SEARCH.BODYTYPE')

几乎相同,但这绝对是我书中的犹太人。旁注:如果我的动作类型嵌套得比这个示例更深,那通常表明它是时候重构并将其分解成更小的模块。

注意:这是所有未经测试的代码