React 中setState 的这两种updater 函数是否相等?
Are these two types of updater functions for setState in React equal?
我最近了解到 updater functions 用于 setState
在 React 中。
现在我已经看到这个概念以两种不同的方式使用。假设我们有一个这样的状态对象:
interface State {
readonly expanded: boolean;
readonly slugs: string[];
}
state: State = { expanded: false, slugs: [] }
我见过像这样使用的更新程序函数:
this.setState(prevState => ({ ...prevState, expanded: !prevState.expanded }));
像这样:
this.setState(({ expanded }) => ({ expanded: !expanded }));
我自己试过了,看看两者的使用是否有区别,但我找不到(除了字符数)。我的直觉告诉我,第一种方式可能更安全,因为第二种方式 state
(在本例中为 slugs
)可能会被覆盖?
编辑: 这个问题已被标记为 的重复问题,但它本质上是不同的,因为我想知道 [=13= 的功能] 而不是关于 TypeScript 的类型注释是如何工作的。为了清楚起见,我只是提供了 TypeScript 类型。很抱歉这个问题造成了混乱。英语不是我的主要语言,我不知道如何更清楚地表达这一点。幸运的是有人理解并完美地回答了这个问题。
如果你查看源代码,尤其是 setState and enqueueSetState,你可以看到以下代码:
if (typeof partialState === 'function') {
partialState = partialState.call(
pu blicInstance,
currentState,
publicInstance.props,
);
}
// Null and undefined are treated as no-ops.
if (partialState === null || partialState === undefined) {
return;
}
this._renderer._newState = {
...currentState,
...partialState,
};
这意味着
this.setState(({ expanded }) => ({ expanded: !expanded }));
最终会是:
state = {...prevState, {expanded: !expanded}}
和
this.setState(prevState => ({ ...prevState, expanded: !prevState.expanded }));
将结束为:
state = {...prevState, ...{...prevState, expanded: !prevState.expanded}}
我认为第二个基本上是对更新程序功能如何工作的理解不足。
这两个语句会导致相同的行为 - expanded
值的更新。
如果你通读 setState
方法的文档,React 期望该方法 return 需要被覆盖的值。 React 将方法的 return 合并到之前的状态对象,并做一个 diff。在第一个子句中,所有其他状态变量都是相同的,除了 expanded
并且在第二个子句中,只有 expanded
发生了变化。
正如 React 的官方文档 State Updates are Merged 所说,React 会将您提供的对象合并到当前状态,而不是覆盖整个状态。
要理解第二个代码,你可以看附件,但我发现你的情况有点不同。因此,在这里回答。
this.setState(prevState => ({ ...prevState, expanded: !prevState.expanded }));
在这里,...prevState
的使用是不必要的。这是因为 react 的 setState 处理特定状态并合并其他状态。
this.setState(prevState => ({ expanded: !prevState.expanded }));
只有在需要更新嵌套在特定状态中的属性时才需要使用合并。例如,如果您有类似的内容:
state = {
people: {
male: 1033,
female: 234,
other: 100
}
}
现在,在这种情况下,您可以在仅更新男性人数时合并人员价值,例如:
this.setState(prevState => ({ people: { ...prevState.people, male: 1045 } }))
可以简单地写成解构:
this.setState(({people}) => ({ people: { ...people, male: 1045 } })
我最近了解到 updater functions 用于 setState
在 React 中。
现在我已经看到这个概念以两种不同的方式使用。假设我们有一个这样的状态对象:
interface State {
readonly expanded: boolean;
readonly slugs: string[];
}
state: State = { expanded: false, slugs: [] }
我见过像这样使用的更新程序函数:
this.setState(prevState => ({ ...prevState, expanded: !prevState.expanded }));
像这样:
this.setState(({ expanded }) => ({ expanded: !expanded }));
我自己试过了,看看两者的使用是否有区别,但我找不到(除了字符数)。我的直觉告诉我,第一种方式可能更安全,因为第二种方式 state
(在本例中为 slugs
)可能会被覆盖?
编辑: 这个问题已被标记为
如果你查看源代码,尤其是 setState and enqueueSetState,你可以看到以下代码:
if (typeof partialState === 'function') {
partialState = partialState.call(
pu blicInstance,
currentState,
publicInstance.props,
);
}
// Null and undefined are treated as no-ops.
if (partialState === null || partialState === undefined) {
return;
}
this._renderer._newState = {
...currentState,
...partialState,
};
这意味着
this.setState(({ expanded }) => ({ expanded: !expanded }));
最终会是:
state = {...prevState, {expanded: !expanded}}
和
this.setState(prevState => ({ ...prevState, expanded: !prevState.expanded }));
将结束为:
state = {...prevState, ...{...prevState, expanded: !prevState.expanded}}
我认为第二个基本上是对更新程序功能如何工作的理解不足。
这两个语句会导致相同的行为 - expanded
值的更新。
如果你通读 setState
方法的文档,React 期望该方法 return 需要被覆盖的值。 React 将方法的 return 合并到之前的状态对象,并做一个 diff。在第一个子句中,所有其他状态变量都是相同的,除了 expanded
并且在第二个子句中,只有 expanded
发生了变化。
正如 React 的官方文档 State Updates are Merged 所说,React 会将您提供的对象合并到当前状态,而不是覆盖整个状态。
要理解第二个代码,你可以看附件
this.setState(prevState => ({ ...prevState, expanded: !prevState.expanded }));
在这里,...prevState
的使用是不必要的。这是因为 react 的 setState 处理特定状态并合并其他状态。
this.setState(prevState => ({ expanded: !prevState.expanded }));
只有在需要更新嵌套在特定状态中的属性时才需要使用合并。例如,如果您有类似的内容:
state = {
people: {
male: 1033,
female: 234,
other: 100
}
}
现在,在这种情况下,您可以在仅更新男性人数时合并人员价值,例如:
this.setState(prevState => ({ people: { ...prevState.people, male: 1045 } }))
可以简单地写成解构:
this.setState(({people}) => ({ people: { ...people, male: 1045 } })