一文帶你掌握React類式組件中setState的應(yīng)用
在 React 類式組件中,我們并不能直接通過修改 state
的值來讓頁(yè)面發(fā)生更新,而是必須通過 setState
的方式讓 React 重新渲染頁(yè)面,setState
來自于哪里呢?來自于繼承 React 的 Component 類中,例如定義一個(gè) App 類: class App extends Component
,在類中我們可以直接通過 this.setState
的方式來修改 state
的值,并讓其調(diào)用 render 函數(shù)重新渲染頁(yè)面。
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()}>修改標(biāo)題</button> </div> ) } }
setState 可以傳入一個(gè)回調(diào)函數(shù)
作用:
- 可以在回調(diào)函數(shù)中編寫新的
state
的邏輯。 - 當(dāng)前的回調(diào)函數(shù)會(huì)將之前的
state
和props
傳遞進(jìn)來。
import React, { Component } from 'react' export class App extends Component { constructor(props) { super(props) this.state = { title: "React" } } changeText() { // 方式二:在setState中傳入回調(diào)函數(shù) this.setState((state, props) => { // 可以獲取之前的 state 和 props 值 console.log(state.title, props) // 可以編寫一些新的對(duì)state處理的邏輯 return { title: state.title + "Native" } } } render() { const { title } = this.state return ( <div> <h1>title: {title}</h1> <button onClick={e => this.changeText()}>修改標(biāo)題</button> </div> ) } }
setState 在 React 的事件處理中是一個(gè)異步調(diào)用
我們并不能在執(zhí)行完 setState
之后立馬拿到最新的 state
的結(jié)果,可以在 setState
中傳入第二個(gè)參數(shù): callback
回調(diào)函數(shù),用來獲取數(shù)據(jù)更新之后(數(shù)據(jù)合并)的最新值。
import React, { Component } from 'react' export class App extends Component { constructor(props) { super(props) this.state = { title: "React" } } changeText() { // 方式三:通過 setState 方法的第二個(gè)參數(shù), 通過回調(diào)函數(shù)拿到更新后的值 this.setState({ title: 'Redux' }, () => { console.log("在回調(diào)函數(shù)中獲取更新后的值:", this.state.title) // Redux }) console.log('因?yàn)楫惒将@取的還是原來的值', this.state.title) // React } render() { const { title } = this.state return ( <div> <h1>title: {title}</h1> <button onClick={e => this.changeText()}>修改標(biāo)題</button> </div> ) } }
setState 的設(shè)計(jì)是異步的
React 中 setState
的設(shè)計(jì)為什么是異步的,針對(duì)這一討論,Redux 的作者認(rèn)為:setState
設(shè)計(jì)成異步,一方面可以顯著提升性能,這是因?yàn)?React 每次調(diào)用 setState
都會(huì)進(jìn)行一次更新,render
函數(shù)就會(huì)被頻繁的調(diào)用,頁(yè)面頻繁的被渲染,為了解決這一問題,批量的進(jìn)行更新是最得體的方法;另一方面可以使 state
和 props
保持同步,因?yàn)榇嬖谝环N情況,如果同步更新 state
,這時(shí)還沒有執(zhí)行 render
函數(shù),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> ) } }
點(diǎn)擊增加按鈕后 count 值變?yōu)?1,因?yàn)?setState
默認(rèn)是一個(gè)異步的方法,默認(rèn)會(huì)收集一段時(shí)間內(nèi)所有的更新, 然后再統(tǒng)一更新 React。出于性能考慮,React 會(huì)把多個(gè) setState()
調(diào)用合并成一個(gè)調(diào)用,所以點(diǎn)擊按鈕之后 count值 為 1,再次點(diǎn)擊其結(jié)果會(huì)加 1 變?yōu)?2。
其原理就是通過 Object.assign()
方法對(duì)舊 state
和更改后的 state
進(jìn)行一個(gè)合并。
要解決合并這個(gè)問題,可以讓 setState()
接收一個(gè)函數(shù)而不是一個(gè)對(duì)象。
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> ) } }
點(diǎn)擊增加按鈕后 count 值變?yōu)?3,再次點(diǎn)擊其結(jié)果會(huì)在基礎(chǔ)上加 3 變?yōu)?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學(xué)習(xí)筆記' }) console.log(this.state.title) // ReactReact學(xué)習(xí)筆記 }, 0) } render() { const { title } = this.state return ( <div> <h1>title: {title}</h1> <button onClick={e => this.changeText()}>修改標(biāo)題</button> </div> ) } }
React18版本之后,所有操作默認(rèn)都是異步處理的。
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學(xué)習(xí)筆記' }) console.log(this.state.title) // React }, 0) } render() { const { title } = this.state return ( <div> <h1>title: {title}</h1> <button onClick={e => this.changeText()}>修改標(biāo)題</button> </div> ) } }
但是官方表示可以通過 flushSync
函數(shù)獲取到同步的結(jié)果。
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(() => { // 執(zhí)行flushSync函數(shù)就可以拿到同步結(jié)果 flushSync(() => { this.setState({ title: 'React學(xué)習(xí)筆記' }) }) console.log(this.state.title) // React學(xué)習(xí)筆記 }, 0) } render() { const { title } = this.state return ( <div> <h1>title: {title}</h1> <button onClick={e => this.changeText()}>修改標(biāo)題</button> </div> ) } }
由此我們可以總結(jié)出 React 中的 setState 還是有很多奧秘的,其背后的設(shè)計(jì)思想是值得我們學(xué)習(xí)的,值的強(qiáng)調(diào)的是,React18 已經(jīng)全面擁抱函數(shù)式組件,React Hooks 已經(jīng)脫穎而出。
到此這篇關(guān)于一文帶你掌握React類式組件中setState的應(yīng)用的文章就介紹到這了,更多相關(guān)React類式組件setState內(nèi)容請(qǐng)搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!
相關(guān)文章
React Hooks獲取數(shù)據(jù)實(shí)現(xiàn)方法介紹
這篇文章主要介紹了react hooks獲取數(shù)據(jù),文中給大家介紹了useState dispatch函數(shù)如何與其使用的Function Component進(jìn)行綁定,實(shí)例代碼給大家介紹的非常詳細(xì),需要的朋友可以參考下2022-10-10antd中form表單的wrapperCol和labelCol問題詳解
最近學(xué)習(xí)中遇到了些問題,所以給大家總結(jié),下面這篇文章主要給大家介紹了關(guān)于antd中form表單的wrapperCol和labelCol問題的相關(guān)資料,文中通過實(shí)例代碼介紹的非常詳細(xì),需要的朋友可以參考下2023-02-02React 使用browserHistory項(xiàng)目訪問404問題解決
這篇文章主要介紹了React 使用browserHistory項(xiàng)目訪問404問題解決,小編覺得挺不錯(cuò)的,現(xiàn)在分享給大家,也給大家做個(gè)參考。一起跟隨小編過來看看吧2018-06-06React不能將useMemo設(shè)置為默認(rèn)方法原因詳解
這篇文章主要為大家介紹了React不能將useMemo設(shè)置為默認(rèn)方法原因詳解,有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進(jìn)步,早日升職加薪<BR>2022-07-07