setState作為react中的重要部分,將對元件 state 的變更排入佇列,並通知 React 需要使用更新後的 state 重新渲染此元件及其子元件。以下這篇文章帶大家了解React中的setState機制,希望對大家有幫助!
state
是React
中的重要概念。我們知道,React
是透過狀態管理來實現對元件的管理。那麼,React
是如何控制元件的狀態的,又是如何利用狀態來管理元件的呢? 【相關推薦:Redis影片教學】
我們都知道,React
透過this.state
來存取state
,透過this.setState()
方法更新state
。當this.setState()
被呼叫的時候,React
會重新呼叫render
方法來重新渲染UI
。
setState
已經是我們非常熟悉的一個API
,然而你真的了解它嗎?下面我們將一起來解密setState
的更新機制。
setState非同步更新
大家剛開始寫React
的時候,通常會寫出this.state.value = 1
這樣的程式碼,這是完全錯誤的寫法。
注意:絕對不要直接修改 this.state,這不僅是一種低效的做法,而且很有可能會被之後的操作替換。
setState
透過一個佇列機制實作state
更新。當執行setState
時,會將需要更新的state
合併後放入狀態對列,而不會立刻更新this.state
,佇列機制可以高效地批量更新state
。如果不透過setState
而直接修改this.state
的值,那麼該state
將不會被放入狀態佇列中,當下次呼叫 setState
並對狀態佇列進行合併時,將會忽略先前直接被修改的 state
,而造成無法預測的錯誤。
因此,應該使用setState
方法來更新state
,同時React
也正是利用狀態佇列機制實現了setState
的非同步更新,避免頻繁地重複更新state
。相關程式碼如下:
// 将新的state合并到状态更新队列中 var nextState = this._processPendingState(nextProps, nextContext); // 根据更新队列和 shouldComponentUpdate 的状态来判断是否需要更新组件 var shouldUpdate = this._pendingForceUpdte || !inst.shouldCompoonentUpdate || inst.shouldComponentUpdate(nextProps, nextState, nextContext0;
setState循環呼叫風險
當呼叫setState
時,實際上會執行enqueueSetState
方法,並對 partialState
以及_pendingStateQueue
更新佇列進行合併操作,最終操作enqueueSetState
執行state
更新。
而performUpdateIfNecessary
方法會取得_pendingElement、_pendingStateQueue、_pendingForceUpdate
,並呼叫receiveComponent
和updateComponent
# 方法進行元件更新。
如果在shouldComponetUpdate
或componentWillUpdate
方法中呼叫setState
, 此時this._pendingStateQueue != null
, 則performUpateIfNecessary
方法就會呼叫updateComponent
方法進行元件更新,但updateComponent
方法又會呼叫shouldComponentUpdate
和方法,因此造成循環調用,使得瀏覽器記憶體佔滿後崩潰。
setState 最終是透過
enqueueUpate#state
#更新,那麼
enqueueUpdate 到底是如何更新
state 的呢?
import React, { Component } from 'react' class Example extends Component { constructor() { super() this.state = { val: 0 } } componentDidMount() { this.setState({val: this.state.val + 1}) console.log(this.state.val) this.setState({val: this.state.val + 1}) console.log(this.state.val) setTimeout(() => { this.setState({val: this.state.val + 1}) console.log(this.state.val) this.setState({val: this.state.val + 1}) console.log(this.state.val) },0) } render() { return null } }上述程式碼中, 4 次
console.log 列印出來的
val 分別是:
0、0、2、3。
enqueueUpdate 到底做了什麼?
下圖是一個簡化的
setState 呼叫棧,注意其中核心的狀態判斷。
setState簡化呼叫堆疊
setState的各種不同表現的呢?
我们先要了解事务跟 setState
的不同表现有什么关系。首先,我们把4次 setState
简单归类,前两次属于一类,因为他们在同一次调用栈中执行,setTimeout
中的两次 setState
属于另一类,因为他们也是在同一次调用栈中执行。我们分析一下这两类 setState
的调用栈。
在 componentDidMount
中直接调用的两次 setState
,其调用栈更加复杂;而setTimeout
中调用的两次 setState
,其调用栈则简单很多。下面我们重点看看第一类 setState
的调用栈,我们发现了 batchedUpdates
方法,原来早在 setState
调用前,已经处于batchedUpdates
执行的事务中了。
那batchedUpdates
方法,又是谁调用的呢?我们再往前追溯一层,原来是 ReactMount.js 中的 _renderNewRootComponent
方法。也就是说,整个将React组件渲染到DOM中的过程就处于一个大的事务中。
接下来的解释就顺理成章了,因为在componentDidMount
中调用setState
时,batchingStrategy
的 isBatchingUpdates
已经被设为true
,所以两次setState
的结果并没有立即生效,而是被放到了dirtyComponents
中。这也解释了两次打印 this.state.val
都是 0
的原因,因为新的 state
还没有被应用到组件中。
componentDidMount
中setState
的调用栈
setTimeout
中setState
的调用栈
再反观 setTimeout
中的两次setState
,因为没有前置的 batchedUpdate
调用,所以 batchingStrategy
的 isBatchingUpates
标志位是false
,也就导致了新的 state
马上生效,没有走到 dirtyComponents
分支。也就是说,setTimeout
中第一次执行 setState
时,this.state.val
为 1
, 而 setState
完成打印后打印时 this.state.val
变成了2
。第二次的 setState
同理。
前面介绍事务时,也提到了其在 React
源码中的多处应用,像 initialize、perform、close、closeAll、motifyAll
等方法出现在调用栈中,都说明当前处于一个事务中。
既然事务这么有用,我们写应用代码时能使用它吗?很可惜,答案是不能。尽管React
不建议我们直接使用事务,但在 React 15.0
之前的版本中还是为开发者提供了 batchedUpdates
方法,它可以解决针对一开始例子中setTimeout
里的两次 setState
导致两次 render
的情况:
import ReactDOM, { unstable_batchedUpates } from 'teact-dom' unstable_batchedUpates(() => { this.setState(val: this.state.val + 1) this.setState(val: this.state.val + 1) })
在 React 15.0
以及之后版本中,已经彻底将 batchUpdates
这个 API
移除了,因此不再建议开发者使用它。
总结
在使用React
的setState
的过程中,了解setState
的实现原理,对setState
异步更新、setState
循环调用风险、setState
调用栈等进行更加全面的了解,才能让我们在遇到相关问题的时候更加游刃有余。
更多编程相关知识,请访问:编程入门!!
以上是深入了解React中setState的更新機制的詳細內容。更多資訊請關注PHP中文網其他相關文章!

在react中,canvas用于绘制各种图表、动画等;可以利用“react-konva”插件使用canvas,该插件是一个canvas第三方库,用于使用React操作canvas绘制复杂的画布图形,并提供了元素的事件机制和拖放操作的支持。

在react中,antd是基于Ant Design的React UI组件库,主要用于研发企业级中后台产品;dva是一个基于redux和“redux-saga”的数据流方案,内置了“react-router”和fetch,可理解为应用框架。

React不是双向数据流,而是单向数据流。单向数据流是指数据在某个节点被改动后,只会影响一个方向上的其他节点;React中的表现就是数据主要通过props从父节点传递到子节点,若父级的某个props改变了,React会重渲染所有子节点。

因为在react中需要利用到webpack,而webpack依赖nodejs;webpack是一个模块打包机,在执行打包压缩的时候是依赖nodejs的,没有nodejs就不能使用webpack,所以react需要使用nodejs。

在react中,forceupdate()用于强制使组件跳过shouldComponentUpdate(),直接调用render(),可以触发组件的正常生命周期方法,语法为“component.forceUpdate(callback)”。

react是组件化开发;组件化是React的核心思想,可以开发出一个个独立可复用的小组件来构造应用,任何的应用都会被抽象成一颗组件树,组件化开发也就是将一个页面拆分成一个个小的功能模块,每个功能完成自己这部分独立功能。

react与vue的虚拟dom没有区别;react和vue的虚拟dom都是用js对象来模拟真实DOM,用虚拟DOM的diff来最小化更新真实DOM,可以减小不必要的性能损耗,按颗粒度分为不同的类型比较同层级dom节点,进行增、删、移的操作。

react和reactdom的区别是:ReactDom只做和浏览器或DOM相关的操作,例如“ReactDOM.findDOMNode()”操作;而react负责除浏览器和DOM以外的相关操作,ReactDom是React的一部分。


熱AI工具

Undresser.AI Undress
人工智慧驅動的應用程序,用於創建逼真的裸體照片

AI Clothes Remover
用於從照片中去除衣服的線上人工智慧工具。

Undress AI Tool
免費脫衣圖片

Clothoff.io
AI脫衣器

AI Hentai Generator
免費產生 AI 無盡。

熱門文章

熱工具

WebStorm Mac版
好用的JavaScript開發工具

MinGW - Minimalist GNU for Windows
這個專案正在遷移到osdn.net/projects/mingw的過程中,你可以繼續在那裡關注我們。 MinGW:GNU編譯器集合(GCC)的本機Windows移植版本,可自由分發的導入函式庫和用於建置本機Windows應用程式的頭檔;包括對MSVC執行時間的擴展,以支援C99功能。 MinGW的所有軟體都可以在64位元Windows平台上運作。

Dreamweaver CS6
視覺化網頁開發工具

Atom編輯器mac版下載
最受歡迎的的開源編輯器

SublimeText3 英文版
推薦:為Win版本,支援程式碼提示!