2017-01-01 60 views
3

方面变化值深Redux的状态

我渲染形式一组动态文本元素。我已经使用normalizr principles规范了我的状态,所以有一个elementIds数组和一个包含elementIds引用的元素属性的对象(请参阅下面代码示例中的初始状态)。

目的

我的目的是简单地对两个渲染的元素是可编辑的。我使用onChange回调函数成功地将一个动作CHANGE_ELEMENT_VALUE分配给我的商店,在reducer中可以使用action.id(引用已更改元素的id)和action.value(新值)(请参阅下面的代码)。

问题

我的问题是,当我键入文本字段没有发生变化,即使我可以看到使用devtools Redux的扩展状态改变。我的理解是,反应并不能识别状态变化,因为变化是深入的状态,而且我没有成功创建一个新的状态对象,我可能以某种方式引用旧的实例。

减速码

下面是我的拙劣企图迫使一个新的状态对象。我假设它不工作,因为我的组件没有被重新渲染。它也显得非常不雅。

let initialState = { 
    isLoading: false, 
    data: { 
     elementIds: ['name', 'email'], 
     elements: { 
      'name': {'id': 'name', 'value':'ben'}, 
      'email': {'id':'email', 'value':'[email protected]'}, 
     }, 
    }, 
    error: false 
} 

function formReducer(state = initialState, action = null) { 
    switch(action.type) { 
     case types.CHANGE_ELEMENT_VALUE: 
      let newData = Object.assign(state.data) 
      newData.elements[action.id].value = action.value 
      return {...state, data: newData} 

     default: 
      return state; 
    } 
} 

export default formReducer; 
+0

我注意到的第一个问题是您滥用Object.assign。如果你测试它,你可以看到'newData === state.data',这是因为第一个参数是目标。一般来说,你总是会有这个深层次克隆对象的“问题”(如果结构是动态的,它会变得更丑),所以下面的答案可能对你有用。我个人使用https://www.npmjs.com/package/icepick –

回答

2

,您可以利用的immutability-helper npm package并在减速机更新你的价值观

import update from 'immutability-helper'; 

let initialState = { 
    isLoading: false, 
    data: { 
     elementIds: ['name', 'email'], 
     elements: { 
      'name': {'id': 'name', 'value':'ben'}, 
      'email': {'id':'email', 'value':'[email protected]'}, 
     }, 
    }, 
    error: false 
} 

function formReducer(state = initialState, action = null) { 
    switch(action.type) { 
     case types.CHANGE_ELEMENT_VALUE: 
      return update(state, { 
       data : { 
        elements: { 
         [action.id]: { 
           value: { 
            $set: 'new value' 
           } 
          } 
        } 
       } 
      }) 

     default: 
      return state; 
    } 
} 

export default formReducer; 

update()提供简单句法糖围绕此模式使 更容易编写此代码。尽管语法花了一些时间去使用 (尽管它受MongoDB查询语言的启发),但没有多余的余地,它是静态分析的,并且它不比更改版本更容易输入 。

+0

谢谢@ shubham-khatri。你或其他人是否有意见认为这是否比上面提到的深度延伸选项更好? – xanld

1

Object.assign只能操作一级深度;即它不递归地克隆整个对象树。因此,您的顶级对象被克隆,但它不会触发重新渲染,因为您的Reducer会在克隆的对象中突变一个值。

我会建议寻找到deep-extend包和更新您的状态如下:

import extend from 'deep-extend'; 

... 

return extend(state, { 
    elements: { 
    [key]: value 
    } 
}); 
+0

这看起来很方便。我是否应该对任何表现处罚或对我的状态结构的担忧以及我不得不在整个关键笔画上复制树的整个部分这一事实感到担心,只需将一个值改为一个字符? – xanld