【问题标题】:Are these two types of updater functions for setState in React equal?React 中 setState 的这两种类型的更新函数是否相等?
【发布时间】:2018-12-02 09:02:21
【问题描述】:

我最近在 React 中了解到 updater functions 用于 setState

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

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

编辑:这个问题已被标记为与this question 重复,但它本质上是不同的,因为我想知道setState 的功能,而不是TypeScript 的类型注释如何工作.为了清楚起见,我只是提供了 TypeScript 类型。很抱歉这个问题引起了混乱。英语不是我的主要语言,我不知道如何更清楚地表达这一点。幸运的是,有人完美理解并回答了这个问题。

【问题讨论】:

  • 另外,请查看this post 以获得更多帮助。
  • @BhojendraRauniyar 我相信这里的类型声明只是为了演示state的内部结构。
  • @skyboyer OP 不会与 state 混淆,而是使用不同的语法以及解构有助于理解的地方。
  • @BhojendraRauniyar 是的,他在问setState 的功能和返回对象版本在这种情况下是否有任何区别。

标签: javascript reactjs typescript setstate


【解决方案1】:

如果你查看源代码,尤其是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}}

我认为第二个基本上是对更新程序功能如何工作的理解不足。

【讨论】:

  • @BhojendraRauniyar 你提到的那个似乎与这个问题没有任何关系。
  • state = {...prevState, {...prevState, expanded: !prevState.expanded}} 应该是state = {...prevState, ...{...prevState, expanded: !prevState.expanded}}(否则会引发语法错误)
  • 当实际需要展开运算符时,能否请您在state 中添加一些关于嵌套对象的注释?
  • 谢谢!这正好回答了我的问题。
【解决方案2】:

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

【讨论】:

    【解决方案3】:

    这两个语句将导致相同的行为 - 更新 expanded 值。 如果您阅读了setState 方法的文档,React 期望该方法返回需要被覆盖的值。 React 将方法的返回合并到前一个状态对象并做一个 diff。在第一个子句中,所有其他状态变量都相同,除了 expanded 和在第二个子句中,只有 expanded 发生了变异。

    【讨论】:

      【解决方案4】:

      要理解第二个代码,您可以查看附件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 } })
      

      【讨论】:

      • 太棒了,这进一步增强了 Sulthan 的回答!谢谢你们的帮助。
      猜你喜欢
      • 2017-02-01
      • 1970-01-01
      • 2011-08-29
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2021-03-18
      相关资源
      最近更新 更多