1. 基本使用

要点:

  1. 成员属性 state 它是一个特殊的属性,它是当前类的私有数据,只有在当前的组件中才能操作里面的数据
  2. 状态( state )即数据,是组件内部的私有数据,只能在组件内部使用,和vue中data差不多,不过它没有像vue中的data进行了数据劫持
  3. state的值是对象,表示一个组件中可以有多个数据
  4. 通过this.state来获取状态,react 中没有做数据代理
  5. 想要修改 state 数据值同时让视图更新则需要调用专用的方法 this.setState
  6. state 它是类的一个成员属性
  7. state 中的数据可读可写的

使用:

import React, { Component } from 'react';
class App extends Component {
  // 初始化方式1
  // state = {
  //   num: 100
  // }
  // 初始化方式2
  constructor(props) {
    super(props);
    this.state = {
      num: 100
    }
  }
  addNum(evt, n = 1) {
    // 同步修改数据,它不会触发视图更新
    this.state.num  = n
    this.forceUpdate()
    console.log(this.state.num);
  }
  render() {
    return (
      <div>
        {/* 在视图中读取state中的数据 */}
        <h3>{this.state.num}</h3>
        <button onClick={evt => this.addNum(evt, 2)}>累加</button>
      </div>
    );
  }
}
export default App;

2. 使用setState操作state数据

概述:

修改 state 中的 num 属性数据的同时,让视图更新,用到专门用来修改 state 中数据的方法 setState。

语法:

# 语法1
this.setState({
    key:value
})
# 语法2  推荐
this.setState(state => {
    return {key:value}
})

使用:

import React, { Component } from 'react';
class App extends Component {
  state = {
    num: 100
  }
  addNum(evt, n = 1) {
    // 对象方式更新 批处理  => 数组【队列】   虚拟dom比对
    // 它是一个异步操作
    this.setState({
      num: this.state.num   1
    })
    console.log(this.state.num);
    // this.setState({
    //   num: this.state.num   1
    // }, () => {
    //   // 回调函数中就可以得到最新的状态数据
    //   console.log(this.state.num);
    // })
  }
  render() {
    return (
      <div>
        {/* 在视图中读取state中的数据 */}
        <h3>{this.state.num}</h3>
        <button onClick={evt => this.addNum(evt, 2)}>累加</button>
      </div>
    );
  }
}
export default App;

注意:

注意执行结果中,虽然视图发生了更新,但是控制台打印 state 中的数据并没有发生改变,说明这里的更新数据是异步操作。

之所以是异步操作,是因为 React 在这里做了批处理。即当执行多次修改数据的操作时,React 并不会立即执行,而是将这些操作存入一个异步队列中,然后再进行统一处理,这样做可以提升性能。假如我现在要修改 3 次数据,不用批处理需要更新视图 3 次,而如果进行批处理的话,只需要更新视图一次。更新视图需要进行 dom 比对,只比 1 次显然比比对 3 次性能更好。

关于 setState 方法(React 批处理)中的对象合并:

import React, { Component } from 'react';
class App extends Component {
  state = {
    num: 100
  }
  addNum(evt, n = 1) {
    this.setState({
      num: this.state.num   1
    })
    this.setState({
      num: this.state.num   2
    })
    this.setState({
      num: this.state.num   3
    })
    console.log(this.state.num);
    // 函数,它不会合并,它会依次执行  == 建议多用函数方式,保证数据完整性
    // this.setState(state => ({
    //   num: state.num   1
    // }))
    // this.setState(state => ({
    //   num: state.num   2
    // }))
    // this.setState(state => ({
    //   num: state.num   3
    // }))
    // console.log(this.state.num);//6
  }
  render() {
    return (
      <div>
        {/* 在视图中读取state中的数据 */}
        <h3>{this.state.num}</h3>
        <button onClick={evt => this.addNum(evt, 2)}>累加</button>
      </div>
    );
  }
}
export default App;

从图中运行结果可以看出,当我们多次修改数据时,视图只针对最后一次修改作出渲染。这是因为在 React 批处理中(批处理队列是一个集合,这里看作是一个对象),会进行对象合并。什么意思呢?首先对象的 key 值是唯一的,当 key 值 num 已经存在时,再传 num 会对对象中已经存在的 num 进行修改,即对象中有效的 num 的值是最后一次操作:this.state.num 3

补充说明:批处理队列的底层进行的是[...obj1,...obj2]的操作,所以重复的项只会出现一次。而函数方式的批处理进行的是[fn1,fn2...],所以会依次执行。这里的解释过于牵强和抽象,只是为了简单理解和记忆,更加完整的阐述需要了解底层之后,再加深理解。

关于 setState 方法的同步操作:

react17 及之前版本,如果你把当前的操作不写在合成事件中,则 setState 它就是同步的,react18全是异步的。

setState 在执行的过程中,它会判断当的执行环境,如果为宏任务等,则它会立即执行。

也就是说, setState 方法只要写在合成事件处理方法中,它就是异步的;只要不写在合成事件中,它都是同步。(仅限于 react17 及之前版本)

比如 setState 方法写在宏任务中或者写在原生事件中就是同步的。

例如下面这样的写法就是同步操作:

import React, { Component } from 'react';
class App extends Component {
  // setState它是同步的也是异步的
  // 只要写在合成事件处理方法中,它就是异步
  // 只要不写在合成事件中,它都是同步
  state = {
    num: 100
  }
  addNum(evt, n = 1) {
    setTimeout(() => {
      // 写在宏任务中的setState它是同步的
      this.setState({
        num: this.state.num   3
      })
      console.log(this.state.num);
    }, 0);
  }
  // 类似于vue中的mounted方法
  // componentDidMount() {
  //   // 写在原生事件中它的setState也是同步的
  //   // document.onclick = () => {
  //   //   this.setState({
  //   //     num: this.state.num   3
  //   //   })
  //   //   console.log(this.state.num);
  //   // }
  // 
  render() {
    return (
      <div>
        {/* 在视图中读取state中的数据 */}
        <h3>{this.state.num}</h3>
        <button onClick={evt => this.addNum(evt, 2)}>累加</button>
      </div>
    );
  }
}
export default App;

3. 案例-toDoList

import React, { Component } from 'react';
class App extends Component {
  state = {
    todos: []
  }
  onEnter = evt => {
    if (evt.keyCode === 13) {
      let title = evt.target.value.trim()
      // 方案1
      // let todos = this.state.todos.concat({ id: Date.now(), title, done: false })
      // this.setState({ todos })
      // 方案2
      // this.state.todos.push({ id: Date.now(), title, done: false })
      // this.forceUpdate() // 这里也可以写成这一句:this.setState({})
      // 如果你setState写了一个空对象,则它会更新视图一次
      // this.setState({})
      // 如果你写了为null,setState不会做任何事件,相当于没有调用
      // this.setState(null)
      // 方案3:更新数据,推荐,确保数据的完整性
      this.setState(state => ({
        todos: [...state.todos, { id: Date.now(), title, done: false }]
      }), () => evt.target.value = '')
    }
  }
  del = tid => () => {
    this.setState(state => ({
      todos: state.todos.filter(({ id }) => id != tid)
    }))
  }
  delIndex = index => () => {
    this.state.todos.splice(index, 1)
    this.setState({})
  }
  render() {
    return (
      <div>
        <div>
          <input type="text" onKeyUp={this.onEnter} />
        </div>
        <hr />
        <ul>
          {
            this.state.todos.map((item, index) => (
              <li key={item.id}>
                <span>{item.title}</span>
                {/* 按 id 删除 */}
                <span onClick={this.del(item.id)}>删除</span>
                {/* 按索引删除 */}
                <span onClick={this.delIndex(index)}>删除</span>
              </li>
            ))
          }
        </ul>
      </div>
    );
  }
}
export default App;

注意:

setState 还有两种扩展用法:

如果你setState写了一个空对象,则它会更新视图一次

this.setState({})

如果你写了为null,setState不会做任何事件,相当于没有调用

this.setState(null)

4. 案例-购物车

import React, { Component } from 'react';
class App extends Component {
  state = {
    carts: [
      { id: 1, name: '水果手机14', price: 1, num: 1 },
      { id: 2, name: '大米手机14', price: 1, num: 2 },
      { id: 3, name: '一般手机14', price: 1, num: 3 },
    ]
  }
  setNum = (n, index) => {
    // 方案1
    this.state.carts[index]['num']  = n
    if (this.state.carts[index]['num'] <= 1) this.state.carts[index]['num'] = 1
    if (this.state.carts[index]['num'] >= 5) this.state.carts[index]['num'] = 5
    this.setState({})
    // 方案2
    // this.setState(state => {
    //   state.carts[index]['num']  = n
    //   let carts = state.carts
    //   return { carts }// 同等于 return {carts:carts}
    // })
  }
  totalPrice = () => {
    return this.state.carts.reduce((p, c) => {
      p  = c.num * c.price
      return p
    }, 0)
  }
  render() {
    return (
      <div>
        <table width='600' border='1'>
          <thead>
            <tr>
              <th>ID</th>
              <th>名称</th>
              <th>价格</th>
              <th>数量</th>
            </tr>
          </thead>
          <tbody>
            {
              this.state.carts.map((item, index) => (
                <tr key={item.id}>
                  <td>{item.id}</td>
                  <td>{item.name}</td>
                  <td>{item.price}</td>
                  <td>
                    <button onClick={() => this.setNum(-1, index)}>---</button>
                    <span>{item.num}</span>
                    <button onClick={() => this.setNum(1, index)}>   </button>
                  </td>
                </tr>
              ))
            }
          </tbody>
        </table>
        <hr />
        <h3>{this.totalPrice()}</h3>
      </div>
    );
  }
}
export default App;

到此这篇关于React state状态属性详细讲解的文章就介绍到这了,更多相关React state状态内容请搜索Devmax以前的文章或继续浏览下面的相关文章希望大家以后多多支持Devmax!

React state状态属性详细讲解的更多相关文章

  1. ios – React native链接到另一个应用程序

    如果是错误的,有人知道如何调用正确的吗?

  2. ios – React Native – 在异步操作后导航

    我正在使用ReactNative和Redux开发移动应用程序,我正面临着软件设计问题.我想调用RESTAPI进行登录,如果该操作成功,则导航到主视图.我正在使用redux和thunk所以我已经实现了异步操作,所以我的主要疑问是:我应该把逻辑导航到主视图?我可以直接从动作访问导航器对象并在那里执行导航吗?.我对组件中的逻辑没有信心.似乎不是一个好习惯.有没有其他方法可以做到这一点?

  3. 在ios中使用带有React Native(0.43.4)的cocoapods的正确方法是什么?

    我已经挖掘了很多帖子试图使用cocoapods为本地ios库设置一个反应原生项目,但我不可避免地在#import中找到了丢失文件的错误.我的AppDelegate.m文件中的语句.什么是使用反应原生的可可豆荚的正确方法?在这篇文章发表时,我目前的RN版本是0.43.4,而我正在使用Xcode8.2.1.这是我的过程,好奇我可能会出错:1)

  4. ios – React Native WebView滚动行为无法按预期工作

    如何确保滚动事件的行为与ReactNative应用程序中的浏览器相同?

  5. ios – React Native – BVLinearGradient – 找不到’React/RCTViewManager.h’文件

    谢谢.解决方法几天前我遇到了完全相同的问题.问题是在构建应用程序时React尚未链接.试试这个:转到Product=>Scheme=>管理方案…=>点击你的应用程序Scheme,然后点击Edit=>转到Build选项卡=>取消选中ParallelizeBuild然后点击标志添加目标=>搜索React,选择第一个名为React的目标,然后单击Add然后在目标列表中选择React并将其向上拖动到该列表中的第一个.然后转到Product=>再次清理并构建项目.这应该有所帮助.

  6. ios – React Native – NSNumber无法转换为NSString

    解决方法在你的fontWeight()函数中也许变成:

  7. ios – React native error – react-native-xcode.sh:line 45:react-native:command not found命令/ bin/sh失败,退出代码127

    尝试构建任何(新的或旧的)项目时出现此错误.我的节点是版本4.2.1,react-native是版本0.1.7.我看过其他有相同问题的人,所以我已经更新了本机的最新版本,但是我仍然无法通过xcode构建任何项目.解决方法要解决此问题,请使用以下步骤:>使用节点版本v4.2.1>cd进入[你的应用]/node_modules/react-native/packager>$sh./packager.s

  8. 反应原生 – 如何通过Xcode构建React Native iOS应用程序到设备?

    我试图将AwesomeProject应用程序构建到设备上.构建成功并启动屏幕显示,但后来我看到一个红色的“无法连接到开发服务器”屏幕.它表示“确保节点服务器正在运行–从Reactroot运行”npmstart“.看起来节点服务器已经运行,因为当我做npm启动时,我收到一个EADDRINUSE消息,表示该端口已经在使用.解决方法从设备访问开发服务器您可以使用开发服务器快速迭代设备.要做到这一点,你的

  9. 静音iOS推送通知与React Native应用程序在后台

    我有一个ReactNative应用程序,我试图获得一个发送到JavaScript处理程序的静默iOS推送通知.我看到的行为是AppDelegate中的didReceiveRemoteNotification函数被调用,但是我的JavaScript中的处理程序不会被调用,除非应用程序在前台,或者最近才被关闭.我很困惑的事情显然是应用程序正在被唤醒,并且它的didReceiveRemoteNotifi

  10. 如何为iOS的React Native设置分析

    所以我已经完成了一个针对iOS的ReactNative项目,但是我想在其中分析.我尝试了react-native-google-analytics软件包,但是问题阻止了它的正常工作.此外,react-native-cordova-plugin软件包只适用于Android,因此插入Cordova插件进行分析的能力现在已成为问题.我也没有Swift/ObjectiveC的经验,所以将完全失去GA的插入.有没有人有任何建议如何连接GoogleAnalytics的ReactNativeforiOS?

随机推荐

  1. js中‘!.’是什么意思

  2. Vue如何指定不编译的文件夹和favicon.ico

    这篇文章主要介绍了Vue如何指定不编译的文件夹和favicon.ico,具有很好的参考价值,希望对大家有所帮助。如有错误或未考虑完全的地方,望不吝赐教

  3. 基于JavaScript编写一个图片转PDF转换器

    本文为大家介绍了一个简单的 JavaScript 项目,可以将图片转换为 PDF 文件。你可以从本地选择任何一张图片,只需点击一下即可将其转换为 PDF 文件,感兴趣的可以动手尝试一下

  4. jquery点赞功能实现代码 点个赞吧!

    点赞功能很多地方都会出现,如何实现爱心点赞功能,这篇文章主要为大家详细介绍了jquery点赞功能实现代码,具有一定的参考价值,感兴趣的小伙伴们可以参考一下

  5. AngularJs上传前预览图片的实例代码

    使用AngularJs进行开发,在项目中,经常会遇到上传图片后,需在一旁预览图片内容,怎么实现这样的功能呢?今天小编给大家分享AugularJs上传前预览图片的实现代码,需要的朋友参考下吧

  6. JavaScript面向对象编程入门教程

    这篇文章主要介绍了JavaScript面向对象编程的相关概念,例如类、对象、属性、方法等面向对象的术语,并以实例讲解各种术语的使用,非常好的一篇面向对象入门教程,其它语言也可以参考哦

  7. jQuery中的通配符选择器使用总结

    通配符在控制input标签时相当好用,这里简单进行了jQuery中的通配符选择器使用总结,需要的朋友可以参考下

  8. javascript 动态调整图片尺寸实现代码

    在自己的网站上更新文章时一个比较常见的问题是:文章插图太宽,使整个网页都变形了。如果对每个插图都先进行缩放再插入的话,太麻烦了。

  9. jquery ajaxfileupload异步上传插件

    这篇文章主要为大家详细介绍了jquery ajaxfileupload异步上传插件,具有一定的参考价值,感兴趣的小伙伴们可以参考一下

  10. React学习之受控组件与数据共享实例分析

    这篇文章主要介绍了React学习之受控组件与数据共享,结合实例形式分析了React受控组件与组件间数据共享相关原理与使用技巧,需要的朋友可以参考下

返回
顶部