React中setState的这两类更新器功能是否相等?

时间:2018-12-02 09:02:21

标签: javascript reactjs typescript setstate

我最近在React中了解了setState的{​​{3}}。

现在我已经看到此概念以两种不同的方式使用。假设我们有一个这样的状态对象:

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)可能会被覆盖?

编辑:该问题被标记为updater functions的重复项,但本质上是不同的,因为我想知道setState的功能,而不是如何TypeScript的类型注释有效。我只是为了清楚起见提供了TypeScript类型。抱歉,这个问题引起了混乱。英语不是我的主要语言,我也不知道如何表达得更清楚。幸运的是,有人完全理解并回答了这个问题。

4 个答案:

答案 0 :(得分:7)

如果您查看源代码,尤其是查看setStateenqueueSetState,则可以看到以下代码:

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}}

我认为第二点基本上对更新器功能的工作原理了解不足。

答案 1 :(得分:3)

正如React的官方文档State Updates are Merged所说,React会将您提供的对象合并到当前状态,而不是覆盖整个状态。

答案 2 :(得分:2)

这两个语句将导致相同的行为-更新expanded值。 如果您阅读了setState方法的文档,React期望该方法返回需要重写的值。 React将方法的返回值合并到先前的状态对象并进行比较。在第一个子句中,所有其他状态变量都相同,除了expanded之外,在第二个子句中,仅expanded被突变。

答案 3 :(得分:1)

要理解第二个代码,您可以查看所附的duplicate post,但我发现您的情况有些不同。因此,在这里回答。

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 } })