IT数码 购物 网址 头条 软件 日历 阅读 图书馆
TxT小说阅读器
↓语音阅读,小说下载,古典文学↓
图片批量下载器
↓批量下载图片,美女图库↓
图片自动播放器
↓图片自动播放器↓
一键清除垃圾
↓轻轻一点,清除系统垃圾↓
开发: C++知识库 Java知识库 JavaScript Python PHP知识库 人工智能 区块链 大数据 移动开发 嵌入式 开发工具 数据结构与算法 开发测试 游戏开发 网络协议 系统运维
教程: HTML教程 CSS教程 JavaScript教程 Go语言教程 JQuery教程 VUE教程 VUE3教程 Bootstrap教程 SQL数据库教程 C语言教程 C++教程 Java教程 Python教程 Python3教程 C#教程
数码: 电脑 笔记本 显卡 显示器 固态硬盘 硬盘 耳机 手机 iphone vivo oppo 小米 华为 单反 装机 图拉丁
 
   -> JavaScript知识库 -> 深入setState -> 正文阅读

[JavaScript知识库]深入setState

问题一:为什么要使用setState

开发中我们并不能通过直接修改state的值来让界面发生更新(数据值本身虽然已经发生了变化,但是界面并没有发生更新),因为当我们修改了state之后,react并没有实现类似于vue2中的object.defineProperty或者vue3中的proxy的方式去监听数据变化从而自动刷新界面,在react中我们必须通过setState去告知render函数数据已经发生了变化(这一点个人感觉vue3中的ref、reactiveAPI类似于setState)但是在react组件中并没有实现setState的方法,而是直接从component原型上面继承过来的。

至于setState是异步还是同步的问题,我们需要根据实际情况而定。

问题二:setState异步更新

this.state = {
    message: "message"
}     
btnClick() {
    this.setState({
        message: '测试'
    })
    console.log(this.state.message);//message
}

这段代码的输出结果为:message。可见setState是异步的操作,也就是说我们并不能在执行完setState之后立马拿到最新的state的结果。那么为什么setState设计为异步呢?

React的核心成员(redux的作者)在github上面对这个问题有对应的回复。

https://github.com/facebook/react/issues/11527

简单总结就是:

? (1)setState设计为异步,可以显著的提高性能:因为如果每次调用setState都进行一次更新,那么意味着render函数会被频繁调用,导致界面不断的重新渲染,这样效率是很低的;而最好的办法就是通过异步操作尽可能的获取到多个更新之后再进行批量更新。

? (2)如果同步更新了state,但是还没有执行render函数或者render执行需要一段时间,那么state和props是无法保持同步更新的:而state和props不能保持一致性,就会在开发中产生很多的问题。

问题三:如何获取setState异步更新的结果

首先需要知道setState(更新的state,回调函数)是可以传入这两个参数的。

方式一:在更新了state之后,可在第二个回调函数中去获取其异步更新的结果。

this.setState({
    message: '测试'
}, () => {
    console.log(this.state.message)//方式一:在第二个参数回调函数里面
})

方式二:在componentDidUpdate生命周期函数中去获取(因为每次重新render时,是会触发这个函数的)

componentDidUpdate() {
    // 方式二: 获取异步更新的state
    console.log(this.state.message);
}

问题四:setState同步更新

方式一:将setState操作放到setTimeout定时器中去执行(无非也就是等待render函数执行完成,从而达到state和props数据的一致性)

increment() {
    setTimeout(() => {
        this.setState({
            message: '测试'
        })
        console.log(this.state.message)
    }, 0)
}

方式二:放在原生的事件里面(在componentDidMount生命周期函数中去操作DOM)

<button id="change">改变文本</button>

componentDidMount() {
    document.getElementById("change").addEventListener('click', () => {
        this.setState({
            message: '测试'
        })
        console.log(this.state.message)
    })
}

问题五:setState数据的合并

源码利用了object.assign去合并的,但是注意只会覆盖原来已有的,并不会覆盖掉其他的。

object.assign({}, this.state, {message: "测试"})

问题六:setState本身的合并

如果多次重复调用setState时,其实只会调用一次,结果并不会累加,因为会进行合并的。

如果希望合并时并进行累加:setState其实也是可以跟一个函数的并且在函数中返回一个对象

this.setState((preState, props) => {
    return {
        counter: preState.counter + 1
    }
} )

问题七:setState的不可变性

import React, { PureComponent } from 'react';

export default class App extends PureComponent {
  constructor(props) {
    super(props);

    // 引用类型
    this.state = {
      friends: [
        { name: "lilei", age: 20 },
        { name: "lily", age: 25 },
        { name: "lucy", age: 22 }
      ]
    }
  }

  render() {
    return (
      <div>
        <h2>好友列表:</h2>
        <ul>
          {
            this.state.friends.map((item, index) => {
              return (
                <li key={item.name}>
                  姓名: {item.name} 
                  年龄: {item.age}
                  <button onClick={e => this.incrementAge(index)}>age+1</button>
                </li>
              )
            })
          }
        </ul>
        <button onClick={e => this.insertData()}>添加数据</button>
      </div>
    )
  }

  insertData() {
    // 1.在开发中不要这样来做
    // const newData = {name: "tom", age: 30}
    // this.state.friends.push(newData);
    // this.setState({
    //   friends: this.state.friends
    // });

    // 2.推荐做法
    //先对原来的数据拷贝一份,之后再在所拷贝的那份数据上去操作,最后再重新赋值给setState
    const newFriends = [...this.state.friends];
    newFriends.push({ name: "tom", age: 30 });
    this.setState({
      friends: newFriends
    })
  }

  incrementAge(index) {
    const newFriends = [...this.state.friends];
    newFriends[index].age += 1;
    this.setState({
      friends: newFriends
    })
  }
}
  JavaScript知识库 最新文章
ES6的相关知识点
react 函数式组件 & react其他一些总结
Vue基础超详细
前端JS也可以连点成线(Vue中运用 AntVG6)
Vue事件处理的基本使用
Vue后台项目的记录 (一)
前后端分离vue跨域,devServer配置proxy代理
TypeScript
初识vuex
vue项目安装包指令收集
上一篇文章      下一篇文章      查看所有文章
加:2021-07-16 11:11:21  更:2021-07-16 11:13:41 
 
开发: C++知识库 Java知识库 JavaScript Python PHP知识库 人工智能 区块链 大数据 移动开发 嵌入式 开发工具 数据结构与算法 开发测试 游戏开发 网络协议 系统运维
教程: HTML教程 CSS教程 JavaScript教程 Go语言教程 JQuery教程 VUE教程 VUE3教程 Bootstrap教程 SQL数据库教程 C语言教程 C++教程 Java教程 Python教程 Python3教程 C#教程
数码: 电脑 笔记本 显卡 显示器 固态硬盘 硬盘 耳机 手机 iphone vivo oppo 小米 华为 单反 装机 图拉丁

360图书馆 购物 三丰科技 阅读网 日历 万年历 2024年5日历 -2024/5/3 10:19:22-

图片自动播放器
↓图片自动播放器↓
TxT小说阅读器
↓语音阅读,小说下载,古典文学↓
一键清除垃圾
↓轻轻一点,清除系统垃圾↓
图片批量下载器
↓批量下载图片,美女图库↓
  网站联系: qq:121756557 email:121756557@qq.com  IT数码