上下文
我正在渲染一个带有动态文本元素集的表单。我使用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;
答案 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
}
});