React 中没有构造函数的初始化状态

2024-03-09

import React, { Component } from 'react';

class Counter extends Component {
  state = { value: 0 };

  increment = () => {
    this.setState(prevState => ({
      value: prevState.value + 1
    }));
  };

  decrement = () => {
    this.setState(prevState => ({
      value: prevState.value - 1
    }));
  };

  render() {
    return (
      <div>
        {this.state.value}
        <button onClick={this.increment}>+</button>
        <button onClick={this.decrement}>-</button>
      </div>
    )
  }
}

通常我看到的是,如果他使用 es6 类,人们会在构造函数中执行 this.state 。如果他不是,他可能会使用 getinitialstate 函数设置状态。但上面的代码(是的,这是一个工作代码),两者都没有使用。我有两个问题,这里的状态是什么?这是一个局部变量吗?如果是的话为什么没有const? prevState 从哪里来?为什么setState要用箭头函数?这不是很容易做到吗this.setState({value:'something'})?


我有 2 个问题,什么是state here?

实例属性,例如设置this.state = {value: 0};在构造函数中。它正在使用公开课领域提案 https://tc39.github.io/proposal-class-public-fields/目前处于第二阶段。(也是如此increment and decrement,它们是实例字段,其值为箭头函数,因此它们闭合this.)

这是一个局部变量吗?

No.

prevState 从哪里来?为什么setState要用箭头函数?仅仅执行 this.setState({value:'something'}) 不是很容易吗?

From 文档 https://facebook.github.io/react/docs/state-and-lifecycle.html#state-updates-may-be-asynchronous:

React 可以批处理多个setState()调用单个更新以提高性能。

Because this.props and this.state可能会异步更新,您不应依赖它们的值来计算下一个状态。

例如,以下代码可能无法更新计数器:

// Wrong
this.setState({
  counter: this.state.counter + this.props.increment,
});

要修复它,请使用第二种形式setState()它接受一个函数而不是一个对象。该函数将接收先前的状态作为第一个参数,并将应用更新时的 props 作为第二个参数:

// Correct
this.setState((prevState, props) => ({
  counter: prevState.counter + props.increment
}));

...这正是引用的代码正在做的事情。这是错误的:

// Wrong
increment = () => {
  this.setState({
    value: this.state.value + 1
  });
};

...因为它依赖于状态this.state,上面告诉我们不要这样做;所以引用的代码会这样做:

increment = () => {
  this.setState(prevState => ({
    value: prevState.value + 1
  }));
};

这是 React 可能以一种不明显的方式批量调用的证据,以及为什么我们需要使用回调版本setState: 在这里,我们有increment and decrement被叫twice每次点击而不是一次(一次通过按钮,一次通过包含按钮的跨度)。点击+ once应该将计数器增加到 2,因为increment被调用两次。但是因为我们还没有使用函数回调版本setState,它没有:其中一个调用increment变成空操作,因为我们使用的是陈旧的this.state.value value:

class Counter extends React.Component {
  state = { value: 0 };

  increment = () => {
    /*
    this.setState(prevState => ({
      value: prevState.value + 1
    }));
    */
    console.log("increment called, this.state.value = " + this.state.value);
    this.setState({
      value: this.state.value + 1
    });
  };
  
  fooup = () => {
    this.increment();
  };

  decrement = () => {
    /*
    this.setState(prevState => ({
      value: prevState.value - 1
    }));
    */
    console.log("decrement called, this.state.value = " + this.state.value);
    this.setState({
      value: this.state.value - 1
    });
  };
  
  foodown = () => {
    this.decrement();
  };

  render() {
    return (
      <div>
        {this.state.value}
        <span onClick={this.fooup}>
          <button onClick={this.increment}>+</button>
        </span>
        <span onClick={this.foodown}>
          <button onClick={this.decrement}>-</button>
        </span>
      </div>
    )
  }
}

ReactDOM.render(
  <Counter />,
  document.getElementById("react")
);
<div id="react"></div>
<script src="https://cdnjs.cloudflare.com/ajax/libs/react/15.1.0/react.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/react/15.1.0/react-dom.min.js"></script>

使用函数回调,它可以正常工作(没有调用increment变为无操作):

class Counter extends React.Component {
  state = { value: 0 };

  increment = () => {
    this.setState(prevState => {
      console.log("Incrementing, prevState.value = " + prevState.value);
      return {
        value: prevState.value + 1
      };
    });
  };
  
  fooup = () => {
    this.increment();
  };

  decrement = () => {
    this.setState(prevState => {
      console.log("Decrementing, prevState.value = " + prevState.value);
      return {
        value: prevState.value - 1
      };
    });
  };
  
  foodown = () => {
    this.decrement();
  };

  render() {
    return (
      <div>
        {this.state.value}
        <span onClick={this.fooup}>
          <button onClick={this.increment}>+</button>
        </span>
        <span onClick={this.foodown}>
          <button onClick={this.decrement}>-</button>
        </span>
      </div>
    )
  }
}

ReactDOM.render(
  <Counter />,
  document.getElementById("react")
);
<div id="react"></div>
<script src="https://cdnjs.cloudflare.com/ajax/libs/react/15.1.0/react.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/react/15.1.0/react-dom.min.js"></script>

当然,在这种情况下,我们可以看看render方法并说“嘿,increment单击期间将被调用两次,我最好使用回调版本setState” 但不要假设它可以安全使用this.state当确定下一个状态时,最佳实践是not假设。在复杂的组件中,可以很容易地以 mutator 方法的作者可能没有想到的方式使用 mutator 方法。因此 React 作者的声明是:

Because this.props and this.state可以异步更新,你不应该依赖它们的值来计算下一个状态.

本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

React 中没有构造函数的初始化状态 的相关文章

随机推荐

  • mysqldb python 转义?还是%s?

    我目前正在使用mysqldb 在 mysqldb 参数中转义字符串的正确方法是什么 注意E lambda x x encode utf 8 1 所以我的连接设置为 charset utf8 这些是我在这些参数中遇到的错误 w1 w2 u 你
  • Prometheus 按标签子字符串分组

    我正在尝试解决在 Prometheus 中按指标进行查询求和和分组的问题 其中分配给指标值的标签对于我的求和和分组要求是唯一的 我有 ElasticSearch 索引的度量采样大小 其中索引名称标记在度量上 索引的命名如下 并放置在标签 i
  • 模板类的重载运算符<< [重复]

    这个问题在这里已经有答案了 我正在尝试实现一种返回流的二叉树方法 我想使用方法返回的流在屏幕中显示树或将树保存在文件中 这两个方法都属于二叉树类 声明 void streamIND ostream const BinaryTree
  • 当我使用“STORED AS AVRO”子句创建 Hive 表时,Avro 架构存储在哪里?

    至少有两种不同的方法来创建由 Avro 数据支持的 Hive 表 基于 Avro 模式创建表 在本例中 存储在 hdfs 中 创建表 users from avro schema 行格式 SERDE org apache hadoop hi
  • std::map 迭代器如何工作?

    C STL 类 std map 使用二叉树实现 O log n 查找 但对于树来说 迭代器如何工作并不是立即显而易见的 运算符在树结构中实际上意味着什么 虽然 下一个元素 的概念在数组中有明显的实现 但对我来说 它在树中并不那么明显 如何实
  • 如何使用 Python 3.7 和 Anaconda 运行 Spyder

    我已经在 Windows 10 计算机上安装了 Anaconda 该计算机附带了 Spyder 和 Python 3 6 但我希望升级到 Python 3 7 使用 Python 3 7 创建 Anaconda 环境很容易 只需使用 con
  • C# 多线程设计示例

    我对 C Net 比较陌生 我正在开发一个需要多线程的桌面应用程序 我想出了下面的模式作为基础 我想知道是否有人可以指出如何在编码 线程安全和高效方面做得更好 希望这有一定道理 public abstract class ThreadMan
  • 如何在 .NET 中使用 Firebase Admin SDK?

    我有一个用 VB Net 编写的 Windows 桌面应用程序 我的服务器需要与 Firebase 连接以将更新发送到该应用程序 Firebase 实时数据库 现在 我可以使用服务帐户中的 数据库机密 来执行此操作 但由于此功能已弃用 我想
  • 检测 Brainfuck 程序中的无限循环

    我写了一个简单的脑残 http en wikipedia org wiki BrainfuckMATLAB 脚本语言的解释器 它被输入随机的 bf 程序来执行 作为遗传算法项目的一部分 我面临的问题是 程序在相当多的情况下会出现无限循环 因
  • 寻找一种更有效的方法来过滤掉 Perl 哈希值

    我的目标是从原始堆栈的记录是not in the 好钥匙 list 我如何以最有效的方式实现这一目标 我目前正在编写的代码感觉很拖沓 我愿意接受建议 请注意 这些值可能会变得非常大 这是我的数据 Main data container my
  • 在 Scala 中顺序组合任意数量的 future

    我是 scala 新手 我尝试在 scala 2 10RC3 中组合多个 Future 这Futures应该按顺序执行 在文件中斯卡拉SIP14 http docs scala lang org sips pending futures p
  • Google Document AI API OCR 响应中的空页面数组

    我目前正在使用 Google Document AI API 通过 OCR 从 PDF 中提取文本 但是 我注意到 OCR 响应中的页面数组始终为空 即使 OCR 操作成功完成并且我能够从文档中检索文本 这是我正在使用的代码的简化版本 fr
  • Mercurial 樱桃采摘更改提交

    比如说 我对代码做了很多更改 并且只需要提交其中的一些更改 Mercurial 有没有办法做到这一点 我知道darcs有这样一个功能 I know hg transplant可以在分支之间执行此操作 但我需要类似的东西来在当前分支中提交代码
  • jQuery Ajax 调用 - 成功时设置变量值[重复]

    这个问题在这里已经有答案了 我正在编写一个应用程序 用于修改服务器中缓存对象的数据 这些修改是通过 ajax 调用执行的 该调用基本上更新该对象的属性 当用户完成工作时 我有一个基本的 保存更改 按钮 允许他们保存数据并刷新缓存的对象 为了
  • Indy HTTP:读取 403 响应内容

    我在使用 Indy HTTP 在 Delphi 中 和 Google Contacts API 时遇到问题 请参阅下页 客户端登录响应 部分 http code google com apis accounts docs AuthForIn
  • 尝试运行 Selenium Webdriver (WebdriverJS) 的示例测试时出现错误

    我正在尝试在文件中运行示例测试google search test js位于 node modules selenium webdriver example 我正在使用 WebdriverJS 并且只安装了selenium webdrive
  • 使用 java 解析器删除 XML 节点

    在下面的示例 XML 中 如果 E 13 如何使用 java 解析器删除整个 B 节点
  • 在 NSLayoutManager 中使用boundingRectForGlyphRange计算字边界时如何消除前导空格

    我正在 iOS 上将多行字符串分解为单词边界 我的解决方案以 NSLayoutManager 的boundingRectForGlyphRange 方法为中心 它几乎可以工作 只是每个单词的矩形向右偏移了几个像素 换句话说 NSLayout
  • 单用户的 Git 工作流程

    我是一家开发少量桌面应用程序和网站的单身商店 几个月前我开始使用 GIT 进行版本控制 我对它相当满意 但我的使用非常笨拙 我想知道单个用户的工作流程应该是什么 现在 我的每个项目文件夹中都有一个 git 文件夹 我每隔一段时间就提交一次更
  • React 中没有构造函数的初始化状态

    import React Component from react class Counter extends Component state value 0 increment gt this setState prevState gt