在redux状态深度改变值

时间:2017-01-01 20:13:46

标签: reactjs redux

上下文

我正在渲染一个带有动态文本元素集的表单。我使用normalizr principles对我的状态进行了规范化,因此有一个elementIds数组和一个包含elementIds引用的元素属性的对象(参见下面代码示例中的初始状态)。

目标

我的目标只是让两个渲染元素可以编辑。我使用onChange回调成功地将动作CHANGE_ELEMENT_VALUE分派给我的商店,并且reducer中有action.id(引用已更改元素的id)和action.value(新值)(参见下面的代码)。 / p>

问题

我的问题是,当我键入时,文本字段不会更改,即使我可以使用devtools redux扩展名查看状态更改。我的理解是,react没有识别状态变化,因为状态变化很深,而且我没有成功创建一个新的状态对象,我可能会以某种方式引用旧实例。

缩减代码

下面是我试图强迫新的状态对象。我假设它不起作用,因为我的组件没有被重新渲染。它看起来也很不优雅。

let initialState = {
    isLoading: false,
    data: {
        elementIds: ['name', 'email'],
        elements: {
            'name': {'id': 'name', 'value':'ben'},
            'email': {'id':'email', 'value':'ben@test.com'},
        },
    },
    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;

2 个答案:

答案 0 :(得分:3)

您可以使用import update from 'immutability-helper'; let initialState = { isLoading: false, data: { elementIds: ['name', 'email'], elements: { 'name': {'id': 'name', 'value':'ben'}, 'email': {'id':'email', 'value':'ben@test.com'}, }, }, 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()
  

private void Payment_Load(object sender, EventArgs e) { NameOfUser.Text = UserAccounts[0].Name; EmailOfUser.Text = UserAccounts[0].Email; PaymentType.Text = UserAccounts[0].PaymentType; double totalCost = 0; foreach (DataGridViewRow row in b1.DataGridView1.SelectedRows) { int index = 0; foreach (DataGridViewCell cell in row.Cells) { totalCost += (double)dataGridView1.Rows[index].Cells[4].Value; } index++; } TotalCost.Text = Convert.ToString(totalCost); } 提供了围绕此模式的简单语法糖   更容易编写此代码。虽然语法需要一点点使用   虽然它受到MongoDB查询语言的启发,但是没有   冗余,它是静态可分析的,而且打字不多   而不是变异版本。

答案 1 :(得分:1)

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

我建议您查看deep-extend包并按如下方式更新您的状态:

import extend from 'deep-extend';

...

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