React state状态属性详细讲解

目录
  • 1. 基本使用
  • 2. 使用setState操作state数据
  • 3. 案例-toDoList
  • 4. 案例-购物车

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状态内容请搜索我们以前的文章或继续浏览下面的相关文章希望大家以后多多支持我们!

(0)

相关推荐

  • React State状态与生命周期的实现方法

    一.实现组件的方法: 组件名称首字母必须大写 1.通过JS函数方式实现组件 <div id="app"></div> <script type="text/babel"> var ReactDiv = document.getElementById('app'); function GetReactComp(){ return <p>我是react组件</p> } const hellocomp = <

  • 浅谈React之状态(State)

    在React当中,当你更新组件的state,然后新的state就会重新渲染到页面中.在这个时候不需要你操作任何DOM.你也可以认为组件在React当中是一个状态机(State Machines).当用户进行操作时会实现不同的状态,然后再渲染到你的页面中,让你的页面与数据始终保持一致. 如何定义State 定义一个合适的State,是正确创建组件的第一步.State必须能代表一个组件UI呈现的完整状态集,即组件的任何UI改变,都可以从State的变化中反映出来:同时,State还必须是代表一个组件

  • React在组件中如何监听redux中state状态的改变

    目录 在组件中监听redux中state状态的改变 解决方式 React和redux的状态处理 在组件中监听redux中state状态的改变 解决方式 1.在组件中引入store 2.在constructor构造器方法中,重写store.subscribe方法(该方法即是监听state状态改变的放过) 组件完整代码如下: import React, { Component } from 'react' import CSSModules from 'react-css-modules'  imp

  • React事件监听和State状态修改方式

    目录 React事件监听和State状态修改 React事件监听相关例子 React事件监听和State状态修改 on*函数可直接使用,但只能使用在html标签上,自己创建的组件标签不可 组件可以增加state状态,修改用setState方法,修改会有缓存,只能保证在渲染到页面之前会改好.所以setState后立马去使用值可能是不对的 狗子组件1:点击会打印bark和run class Dog extends Component {   bark () {     console.log('ba

  • 解决react中useState状态异步更新的问题

    目录 疑惑 状态异步更新带来的问题 问题示例 问题解决 类组件的解决方案 函数组件的解决方案 其他解决方案 结尾 疑惑 相信刚开始使用react函数组件的小伙伴也遇到过一个坑,就是 useState 更新状态是异步更新的,但是react 并没有提供关于这个问题的解决方案.那我们能否使用自己的方法来解决这个问题呢?答案肯定是可以的. 状态异步更新带来的问题 就拿一个比较常见的场景来说.在react项目中,我们想在关闭对话框后再去处理其他业务.但是 useState 的状态是异步更新的.我们通过se

  • React 无状态组件(Stateless Component) 与高阶组件

    无状态组件(Stateless Component) 是 React 0.14 之后推出的,大大增强了编写 React 组件的方便性,也提升了整体的渲染性能. 无状态组件 (Stateless Component) function HelloComponent(props, /* context */) { return <div>Hello {props.name}</div> } ReactDOM.render(<HelloComponent name="Se

  • React state状态属性详细讲解

    目录 1. 基本使用 2. 使用setState操作state数据 3. 案例-toDoList 4. 案例-购物车 1. 基本使用 要点: 成员属性 state 它是一个特殊的属性,它是当前类的私有数据,只有在当前的组件中才能操作里面的数据 状态( state )即数据,是组件内部的私有数据,只能在组件内部使用,和vue中data差不多,不过它没有像vue中的data进行了数据劫持 state的值是对象,表示一个组件中可以有多个数据 通过this.state来获取状态,react 中没有做数据

  • React state状态属性用法讲解

    目录 类组件中的state setState的用法 类组件如何限制state更新视图 setState原理揭秘 函数组件中的state useState的用法 如何监听state的变化 setState(dispatch)更新特点 useState的注意事项 总结 相同点 不同点 类组件中的state setState的用法 React项目中UI改变来源于state的改变,类组件中setState是更新组件,渲染视图的主要方式 基本用法 setState(obj,callback) 第一个参数:

  • React运行机制超详细讲解

    目录 适合人群 写源码之前的必备知识点 JSX 虚拟Dom 原理简介 手写react过程 基本架子的搭建 React的源码 ReactDom.render ReactDom.Component 简单源码 适合人群 本文适合0.5~3年的react开发人员的进阶. 讲讲废话: react的源码,的确是比vue的难度要深一些,本文也是针对初中级,本意了解整个react的执行过程. 写源码之前的必备知识点 JSX 首先我们需要了解什么是JSX. 网络大神的解释:React 使用 JSX 来替代常规的

  • React RenderProps模式超详细讲解

    目录 正文 使用Render Props来完成关注点分离 render prop的prop名不一定叫render 注意点 render prop是一个技术概念.它指的是使用值为function类型的prop来实现React component之间的代码共享. 如果一个组件有一个render属性,并且这个render属性的值为一个返回React element的函数,并且在组件内部的渲染逻辑是通过调用这个函数来完成的.那么,我们就说这个组件使用了render props技术. <DataProvi

  • React渲染机制超详细讲解

    目录 准备工作 render阶段 workloopSync beginWork completeWork commit阶段 commitWork mutation之前 mutation fiber树切换 layout layout之后 总结 准备工作 为了方便讲解,假设我们有下面这样一段代码: function App(){ const [count, setCount] = useState(0) useEffect(() => { setCount(1) }, []) const handl

  • Vue computed计算属性详细讲解

    目录 一.计算属性computed 1.1.什么是计算属性computed 1.2.复杂数据的处理-computed 1.3.计算属性的缓存 1.4.计算属性computed的setter和getter 一.计算属性computed 1.1.什么是计算属性computed computed 是基于它的依赖缓存,只有在它的相关依赖发生改变时才会进行更新.官方文档是这样说的:对于任何包含响应式数据的复杂逻辑,你都应该使用计算属性 1.2.复杂数据的处理-computed 拼接字符串.分数是否及格.m

  • React组件封装中三大核心属性详细介绍

    目录 1.介绍 2.state 概念 演示 3.props 概念 props与state区别 4.refs 概念 refs种类 5.父子组件 什么是父子组件 父子组件之间传值 1.介绍 React组件中默认封装了很多属性,有的是提供给开发者操作的,其中有三个属性非常重要:state.props.refs. 2.state 概念 state是类组件的一个默认属性,用于标识类组件的状态,负责更新UI,让页面动态变化,当state变化时,组件将被重新渲染. 函数组件没有对象属性(babel默认开启了局

  • React生命周期与父子组件间通信知识点详细讲解

    目录 声明周期 声明周期解析 生命周期函数 Constructor componentDidMount componentDidUpdate componentWillUnmount 不常用的生命周期函数 认识组件间的通信 参数propTypes 限制单个元素 默认 Prop 值 对于函数式组件 子组件传递父组件 声明周期 很多的事物都有从创建到销毁的整个过程,这个过程称之为是生命周期: React组件也有自己的生命周期,了解组件的生命周期可以让我们在最合适的地方完成自己想要的功能: 生命周期和

  • React State与生命周期详细介绍

    目录 一.State 1.1 类组件中的State 1.2 函数组件中的State 二.React生命周期 2.1 挂载 2.2 更新 2.3 卸载 2.4 函数式组件useEffect 三.总结 一.State 在React当中,当你更新组件的state,然后新的state就会重新渲染到页面中.在这个时候不需要你操作任何DOM.这和vue中组件的data中的数据是相似的. 1.1 类组件中的State <!DOCTYPE html> <html lang="en"&

随机推荐