一文带你掌握React类式组件中setState的应用
在 React 类式组件中,我们并不能直接通过修改 state
的值来让页面发生更新,而是必须通过 setState
的方式让 React 重新渲染页面,setState
来自于哪里呢?来自于继承 React 的 Component 类中,例如定义一个 App 类: class App extends Component
,在类中我们可以直接通过 this.setState
的方式来修改 state
的值,并让其调用 render 函数重新渲染页面。
setState 的三种写法
基本方式
import React, { Component } from 'react' export class App extends Component { constructor(props) { super(props) this.state = { title: "React" } } changeText() { // 方式一:最基本的使用方式 this.setState({ title: "React类组件" }) } render() { const { title } = this.state return ( <div> <h1>title: {title}</h1> <button onClick={e => this.changeText()}>修改标题</button> </div> ) } }
setState 可以传入一个回调函数
作用:
- 可以在回调函数中编写新的
state
的逻辑。 - 当前的回调函数会将之前的
state
和props
传递进来。
import React, { Component } from 'react' export class App extends Component { constructor(props) { super(props) this.state = { title: "React" } } changeText() { // 方式二:在setState中传入回调函数 this.setState((state, props) => { // 可以获取之前的 state 和 props 值 console.log(state.title, props) // 可以编写一些新的对state处理的逻辑 return { title: state.title + "Native" } } } render() { const { title } = this.state return ( <div> <h1>title: {title}</h1> <button onClick={e => this.changeText()}>修改标题</button> </div> ) } }
setState 在 React 的事件处理中是一个异步调用
我们并不能在执行完 setState
之后立马拿到最新的 state
的结果,可以在 setState
中传入第二个参数: callback
回调函数,用来获取数据更新之后(数据合并)的最新值。
import React, { Component } from 'react' export class App extends Component { constructor(props) { super(props) this.state = { title: "React" } } changeText() { // 方式三:通过 setState 方法的第二个参数, 通过回调函数拿到更新后的值 this.setState({ title: 'Redux' }, () => { console.log("在回调函数中获取更新后的值:", this.state.title) // Redux }) console.log('因为异步获取的还是原来的值', this.state.title) // React } render() { const { title } = this.state return ( <div> <h1>title: {title}</h1> <button onClick={e => this.changeText()}>修改标题</button> </div> ) } }
setState 的设计是异步的
React 中 setState
的设计为什么是异步的,针对这一讨论,Redux 的作者认为:setState
设计成异步,一方面可以显著提升性能,这是因为 React 每次调用 setState
都会进行一次更新,render
函数就会被频繁的调用,页面频繁的被渲染,为了解决这一问题,批量的进行更新是最得体的方法;另一方面可以使 state
和 props
保持同步,因为存在一种情况,如果同步更新 state
,这时还没有执行 render
函数,state
和 props
不能保持同步。
export class App extends Component { constructor(props) { super(props) this.state = { count: 0 } } increment() { this.setState({ count: this.state.count + 1 }) this.setState({ count: this.state.count + 1 }) this.setState({ count: this.state.count + 1 }) console.log(this.state.count) // 1 } render() { const { count } = this.state return ( <div> <h1>{count}</h1> <button onClick={e => this.increment()}>count+1</button> </div> ) } }
点击增加按钮后 count 值变为 1,因为 setState
默认是一个异步的方法,默认会收集一段时间内所有的更新, 然后再统一更新 React。出于性能考虑,React 会把多个 setState()
调用合并成一个调用,所以点击按钮之后 count值 为 1,再次点击其结果会加 1 变为 2。
其原理就是通过 Object.assign()
方法对旧 state
和更改后的 state
进行一个合并。
要解决合并这个问题,可以让 setState()
接收一个函数而不是一个对象。
export class App extends Component { constructor(props) { super(props) this.state = { count: 0 } } increment() { this.setState((state) => { return { count: state.count + 1 } }) this.setState((state) => { return { count: state.count + 1 } }) this.setState((state) => { return { count: state.count + 1 } }) console.log(this.state.count) // 3 } render() { const { count } = this.state return ( <div> <h1>{count}</h1> <button onClick={e => this.increment()}>count+1</button> </div> ) } }
点击增加按钮后 count 值变为 3,再次点击其结果会在基础上加 3 变为 6。
setState 到底是同步的还是异步的
React18 版本之前,在组件生命周期或 React 合成事件中,setState
是异步的;在 setTimeout
或者原生 dom
事件中,setState
是同步的。
import React, { Component } from 'react' export class App extends Component { constructor(props) { super(props) this.state = { title: "React" } } changeText() { setTimeout(() => { // 在react18之前, setTimeout中setState操作, 是同步操作 this.setState({ title: 'React学习笔记' }) console.log(this.state.title) // ReactReact学习笔记 }, 0) } render() { const { title } = this.state return ( <div> <h1>title: {title}</h1> <button onClick={e => this.changeText()}>修改标题</button> </div> ) } }
React18版本之后,所有操作默认都是异步处理的。
import React, { Component } from 'react' export class App extends Component { constructor(props) { super(props) this.state = { title: "React" } } changeText() { setTimeout(() => { // 在react18之后, setTimeout中setState异步操作(批处理) this.setState({ title: 'React学习笔记' }) console.log(this.state.title) // React }, 0) } render() { const { title } = this.state return ( <div> <h1>title: {title}</h1> <button onClick={e => this.changeText()}>修改标题</button> </div> ) } }
但是官方表示可以通过 flushSync
函数获取到同步的结果。
import React, { Component } from 'react' import { flushSync } from 'react-dom' export class App extends Component { constructor(props) { super(props) this.state = { title: "React" } } changeText() { setTimeout(() => { // 执行flushSync函数就可以拿到同步结果 flushSync(() => { this.setState({ title: 'React学习笔记' }) }) console.log(this.state.title) // React学习笔记 }, 0) } render() { const { title } = this.state return ( <div> <h1>title: {title}</h1> <button onClick={e => this.changeText()}>修改标题</button> </div> ) } }
由此我们可以总结出 React 中的 setState 还是有很多奥秘的,其背后的设计思想是值得我们学习的,值的强调的是,React18 已经全面拥抱函数式组件,React Hooks 已经脱颖而出。
到此这篇关于一文带你掌握React类式组件中setState的应用的文章就介绍到这了,更多相关React类式组件setState内容请搜索脚本之家以前的文章或继续浏览下面的相关文章希望大家以后多多支持脚本之家!
相关文章
React、Vue中key的作用详解 (key的内部原理解析)
key是虚拟DOM对象的标识,当状态中的数据发生变化时,Vue会根据[新数据]生成[新的虚拟DOM],本文给大家介绍React、Vue中key的作用详解 (key的内部原理解析),感兴趣的朋友一起看看吧2023-10-10react-native-tab-navigator组件的基本使用示例代码
本篇文章主要介绍了react-native-tab-navigator组件的基本使用示例代码,具有一定的参考价值,有兴趣的可以了解一下2017-09-09如何将你的AngularJS1.x应用迁移至React的方法
本篇文章主要介绍了如何将你的AngularJS1.x应用迁移至React的方法,小编觉得挺不错的,现在分享给大家,也给大家做个参考。一起跟随小编过来看看吧2018-02-02React 正确使用useCallback useMemo的方式
这篇文章主要介绍了React 正确使用useCallback useMemo的方式,文章围绕主题展开详细的内容介绍,具有一定的参考价值,需要的朋友可以参考一下2022-08-08react使用antd的上传组件实现文件表单一起提交功能(完整代码)
最近在做一个后台管理项目,涉及到react相关知识,项目需求需要在表单中带附件提交,怎么实现这个功能呢?下面小编给大家带来了react使用antd的上传组件实现文件表单一起提交功能,一起看看吧2021-06-06
最新评论