gpt4 book ai didi

javascript - 使用 setState() 更新嵌套的 React 状态属性的最佳替代方法是什么?

转载 作者:数据小太阳 更新时间:2023-10-29 05:24:23 26 4
gpt4 key购买 nike

我一直在考虑在这些选项中使用 React setState() 方法更新嵌套属性的最佳方法是什么。考虑到性能并避免与其他可能的并发状态更改发生冲突,我也对更有效的方法持开放态度。

注:我正在使用一个扩展 React.Component 的类组件.如果您使用的是 React.PureComponent更新嵌套属性时必须格外小心,因为如果不更改 state 的任何顶级属性,则可能不会触发重新渲染。 .这是说明此问题的沙箱:

CodeSandbox - Component vs PureComponent and nested state changes

回到这个问题 - 我在这里关心的是性能和其他并发之间可能存在的冲突 setState()更新状态上的嵌套属性时调用:

示例:

假设我正在构建一个表单组件,我将使用以下对象初始化我的表单状态:

this.state = {
isSubmitting: false,
inputs: {
username: {
touched: false,
dirty: false,
valid: false,
invalid: false,
value: 'some_initial_value'
},
email: {
touched: false,
dirty: false,
valid: false,
invalid: false,
value: 'some_initial_value'
}
}
}

根据我的研究,使用 setState() , React 会 浅合并我们传递给它的对象,这意味着它只会检查顶级属性,在这个例子中是 isSubmittinginputs .

因此,我们可以将包含这两个顶级属性( isSubmittinginputs )的完整 newState 对象传递给它,或者我们可以传递其中一个属性,并将其浅合并到前一个状态。

问题 1

您是否同意仅通过 state 才是最佳实践?我们正在更新的顶级属性?例如,如果我们不更新 isSubmitting属性,我们应该避免将它传递给 setState()避免与其他并发调用发生冲突/覆盖 setState()可能已经和这个一起排队了?这样对吗?

在这个例子中,我们将传递一个只有 inputs 的对象。属性(property)。这将避免与另一个 setState() 发生冲突/覆盖可能正在尝试更新 isSubmitting属性(property)。

问题 2

在性能方面,复制当前状态以更改其嵌套属性的最佳方法是什么?

在这种情况下,假设我想设置 state.inputs.username.touched = true .

即使你可以这样做:
this.setState( (state) => {
state.inputs.username.touched = true;
return state;
});

你不应该。因为,来自 React Docs ,我们有:

state is a reference to the component state at the time the change is being applied. It should not be directly mutated. Instead, changes should be represented by building a new object based on the input from state and props.



因此,从上面的摘录我们可以推断出我们应该从当前 state 构建一个新对象。对象,以便根据需要更改和操作它并将其传递给 setState()更新 state .

由于我们正在处理嵌套对象,我们需要一种方法来深度复制对象,并且假设您不想使用任何 3rd 方库 (lodash) 来这样做,我想出的是:
this.setState( (state) => {
let newState = JSON.parse(JSON.stringify(state));
newState.inputs.username.touched = true;
return ({
inputs: newState.inputs
});
});

请注意,当您的 state有嵌套对象你也不应该使用 let newState = Object.assign({},state) .因为那会浅复制 state嵌套对象引用,因此您仍然会直接改变状态,因为 newState.inputs === state.inputs === this.state.inputs会是真的。它们都指向同一个对象 inputs .

但由于 JSON.parse(JSON.stringify(obj))有它的性能限制,并且有一些数据类型或循环数据可能不是 JSON 友好的,你会推荐什么其他方法来深度复制嵌套对象以更新它?

我提出的另一个解决方案如下:
this.setState( (state) => {
let usernameInput = {};
usernameInput['username'] = Object.assign({},state.inputs.username);
usernameInput.username.touched = true;
let newInputs = Object.assign({},state.inputs,usernameInput);

return({
inputs: newInputs
});
};

我在第二个选择中所做的是从我要更新的最里面的对象(在本例中是 username 对象)创建一个新对象。我必须在键 username 中获取这些值,这就是我使用 usernameInput['username'] 的原因因为以后我会把它合并成一个 newInputs目的。一切都使用 Object.assign() 完成.

第二个选项变得更好 performance results .至少好 50%。

关于这个主题的任何其他想法?抱歉问了这么长的问题,但我认为它很好地说明了问题。

编辑:我从以下答案中采用的解决方案:

我的 TextInput 组件 onChange 事件监听器(我通过 React Context 为其提供服务):
onChange={this.context.onChange(this.props.name)}

我的表单组件中的 onChange 函数
onChange(inputName) {
return(

(event) => {
event.preventDefault();
const newValue = event.target.value;

this.setState( (prevState) => {

return({
inputs: {
...prevState.inputs,
[inputName]: {
...prevState.inputs[inputName],
value: newValue
}
}
});
});
}
);
}

最佳答案

我可以想到其他一些方法来实现它。
解构每个嵌套元素并仅覆盖正确的元素:

this.setState(prevState => ({
inputs: {
...prevState.inputs,
username: {
...prevState.inputs.username,
touched: true
}
}
}))
使用解构运算符复制您的输入:
this.setState(prevState => {
const inputs = {...prevState.inputs};
inputs.username.touched = true;
return { inputs }
})

编辑
使用计算属性的第一个解决方案:
this.setState(prevState => ({
inputs: {
...prevState.inputs,
[field]: {
...prevState.inputs.[field],
[action]: value
}
}
}))

关于javascript - 使用 setState() 更新嵌套的 React 状态属性的最佳替代方法是什么?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/54445040/

26 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com