React Redux-Reducer突变

时间:2018-09-21 16:03:22

标签: javascript json reactjs redux

我有一个化简器,其中通过创建浅表副本来改变当前状态对象的状态。减速器的工作方式是更新存储的对象template中的值,然后返回完整状态的对象。 Reducer确实更新了存储,并且我能够看到刷新的更改,并且从localStorage重新生成了持久状态。但是,使用connect()订阅的组件不会得到重新渲染。我该如何编写这种化简为不变异状态的正确方法?

减速器

case UPDATE_STYLE:
  // Update the style value of the template
  let newState = {
    ...state
  }
  newState
      .templates[action.payload.selectedTemplateType]
      .content[action.payload.selectedTemplate]
      .template
      .styles[action.payload.styleKey][action.payload.fieldKey]
      .value = action.payload.value;

  // mutated state - not firing rerenders
  return newState;

发出调度呼叫(有效):

onStyleChange(styleKey, fieldKey, value){
    this.props.dispatch(
      updateStyle(selectedTemplateType, selectedTemplate, styleKey, fieldKey, value)
    );
  }

子组件的连接方式(不渲染)

const mapStateToProps = (state) => ({
  templates: state.templates.templates,
  selectedTemplateType: state.templateTypeSelection.selectedTemplateType,
  selectedTemplate: state.templateSelection.selectedTemplate
})

export default connect(mapStateToProps)(Index)

2 个答案:

答案 0 :(得分:0)

在化简器中,处理完操作后,对象state.templateTypeSelection.selectedTemplateType是同一对象,即使对象内部的某些属性发生了变化。其他道具也有同样的问题。因此,对于组件来说,道具是相同的道具,因此不会重新渲染组件。

有一些解决方案。 1使变径器状态变平。 (似乎不适合您)2要深度复制化简器状态。 3当执行mapStateToProps时,请尝试映射最里面的属性,而不是顶层属性。

对于解决方案2,您可以做的是为reducer状态的top属性创建类。例如,您可以为TemplateTypeSelection创建一个名为state.templateTyepeSelection的类。在reducer中处理动作时,对于新状态,请使用new TemplateTypeSelection(prevState.templateTypeSelection)为state.templateTypeSelection创建一个新对象(您可能希望使用构造函数对state.templateTypeSelection进行浅表复制)。由于state.templateTypeSelection现在是一个新对象,因此您的组件应该现在可以重新呈现。这种方法的问题在于,由于每次处理一个动作时,您都会创建一个新对象,因此可能会有一些不必要的重新渲染。 (这只是一个示例,可能不是一个好例子,因为在您的组件中,您连接的是state.templateTypeSelection.selectedTemplateType,而不是state.templateTypeSelection。希望您能明白。)

根据我的经验,方法2和3的组合效果最好。另外,您可能需要考虑将减速器分成几个减速器。

答案 1 :(得分:0)

另一篇文章已经提到使用深拷贝作为快速解决方案(尽管您可能会失去性能)。但是,尽管有些棘手,但扩展语法(...)可能会为您带来帮助:

let newState = { ...state, templates: {
  { ...state.templates, [action.payload.selectedTemplateType]: {
    { ...state.templates[action.payload.selectedTemplateType], content: {
      { ...state.templates[action.payload.selectedTemplateType].content, [ // and so on

至少,您只会为实际更改的内容创建新对象。

关于这一点:您可能想看看immutableJS,它为此提供了很多帮助,并且不太容易出错。例如,有mergeDeep可以提供帮助。

当您不想进行如此深刻的过渡时,npm上也有深度合并模块(仅Google表示“合并深npm”);我只是实际上没有尝试过任何一个...