成人国产在线小视频_日韩寡妇人妻调教在线播放_色成人www永久在线观看_2018国产精品久久_亚洲欧美高清在线30p_亚洲少妇综合一区_黄色在线播放国产_亚洲另类技巧小说校园_国产主播xx日韩_a级毛片在线免费

資訊專欄INFORMATION COLUMN

從setState, forceUpdate, unstable_batchedUpdates看Re

Simon_Zhou / 1213人閱讀

摘要:是事件回調(diào),有時(shí)機(jī)執(zhí)行邏輯,所以為,,是合并的,結(jié)束之后被重新設(shè)置為。沒(méi)有控制權(quán)的情況有很多回調(diào),網(wǎng)絡(luò)回調(diào)等等。的說(shuō)明從函數(shù)名上理解強(qiáng)制更新。所以可以簡(jiǎn)單的理解為,只不過(guò)這個(gè)是不調(diào)用自己的聲明周期的。

setState同步異步問(wèn)題,React批量更新一直是一個(gè)比較模糊的問(wèn)題,本文希望從框架設(shè)計(jì)的角度說(shuō)明一下這個(gè)問(wèn)題。

React有個(gè)UI = f(data) 公式:UI是由data推導(dǎo)出來(lái)的,所以在寫應(yīng)用的時(shí)候,我們只需要關(guān)心數(shù)據(jù)的改變,只需data ---> data", 那么UI ---> UI",在這個(gè)過(guò)程中,我們其實(shí)并不關(guān)心UI是怎么變化到UI‘的(即DOM的變化),這部分工作是React替我們處理了。

那么React是如何知道當(dāng)數(shù)據(jù)變化的時(shí)候,需要修改哪些DOM的呢?最簡(jiǎn)單暴力的是,每次都重新構(gòu)建整個(gè)DOM樹(shù)。實(shí)際上,React使用的是一種叫virtual-dom的技術(shù):用JS對(duì)象來(lái)表示DOM結(jié)構(gòu),通過(guò)比較前后JS對(duì)象的差異,來(lái)獲得DOM樹(shù)的增量修改。virtual-dom通過(guò)暴力的js計(jì)算,大大減少了DOM操作,讓UI = f(data)這種模型性能不是那么的慢,當(dāng)然你用原生JS/jquery直接操作DOM永遠(yuǎn)是最快的。

setState 批量更新

除了virtual-dom的優(yōu)化,減少數(shù)據(jù)更新的頻率是另外一種手段,也就是React的批量更新。 比如:

g() {
   this.setState({
        age: 18
    })
    this.setState({
        color: "black‘
    })
}

f() {
    this.setState({
        name: "yank"
    })
    this.g()
}

會(huì)被React合成為一次setState調(diào)用

f() {
    this.setState({
        name: "yank",
        age: 18, 
        color: "black"
    })
}

我們通過(guò)偽碼大概看一下setState是如何合并的。

setState實(shí)現(xiàn)

setState(newState) {
    if (this.canMerge) {
        this.updateQueue.push(newState)
        return 
    }
    
    // 下面是真正的更新: dom-diff, lifeCycle...
    ...
}

然后f方法調(diào)用

g() {
   this.setState({
        age: 18
    })
    this.setState({
        color: "black‘
    })
}

f() {
    this.canMerge = true
    
    this.setState({
        name: "yank"
    })
    this.g()
    
    this.canMerge = false
    // 通過(guò)this.updateQueue合并出finalState
    const finalState = ...  
    // 此時(shí)canMerge 已經(jīng)為false 故而走入時(shí)機(jī)更新邏輯
    this.setState(finaleState) 
}

可以看出 setState首先會(huì)判斷是否可以合并,如果可以合并,就直接返回了。

不過(guò)有同學(xué)會(huì)問(wèn):在使用React的時(shí)候,我并沒(méi)有設(shè)置this.canMerge呀?我們的確沒(méi)有,是React隱式的幫我們?cè)O(shè)置了!事件處理函數(shù),聲明周期,這些函數(shù)的執(zhí)行是發(fā)生在React內(nèi)部的,React對(duì)它們有完全的控制權(quán)。

class A extends React.Component {
    componentDidMount() {
        console.log("...")
    }

    render() {
        return (
{ console.log("hi") }}>
} }

在執(zhí)行componentDidMount前后,React會(huì)執(zhí)行canMerge邏輯,事件處理函數(shù)也是一樣,React委托代理了所有的事件,在執(zhí)行你的處理函數(shù)函數(shù)之前,會(huì)執(zhí)行React邏輯,這樣React也是有時(shí)機(jī)執(zhí)行canMerge邏輯的。

批量更新是極好滴!我們當(dāng)然希望任何setState都可以被批量,關(guān)鍵點(diǎn)在于React是否有時(shí)機(jī)執(zhí)行canMerge邏輯,也就是React對(duì)目標(biāo)函數(shù)有沒(méi)有控制權(quán)。如果沒(méi)有控制權(quán),一旦setState提前返回了,就再也沒(méi)有機(jī)會(huì)應(yīng)用這次更新了。

class A extends React.Component {
    handleClick = () => {
        this.setState({x: 1})
        this.setState({x: 2})
        this.setState({x: 3})
        
        setTimeout(() => {
            this.setState({x: 4})
            this.setState({x: 5})
            this.setState({x: 6})
        }, 0)
    }    
    
    render() {
        return (
} }

handleClick 是事件回調(diào),React有時(shí)機(jī)執(zhí)行canMerge邏輯,所以x為1,2,3是合并的,handleClick結(jié)束之后canMerge被重新設(shè)置為false。注意這里有一個(gè)setTimeout(fn, 0)。 這個(gè)fn會(huì)在handleClick之后調(diào)用,而React對(duì)setTimeout并沒(méi)有控制權(quán),React無(wú)法在setTimeout前后執(zhí)行canMerge邏輯,所以x為4,5,6是無(wú)法合并的,所以fn這里會(huì)存在3次dom-diff。React沒(méi)有控制權(quán)的情況有很多: Promise.then(fn), fetch回調(diào),xhr網(wǎng)絡(luò)回調(diào)等等。

unstable_batchedUpdates 手動(dòng)合并

那x為4,5,6有辦法合并嗎?是可以的,需要用unstable_batchedUpdates這個(gè)API,如下:

class A extends React.Component {
    handleClick = () => {
        this.setState({x: 1})
        this.setState({x: 2})
        this.setState({x: 3})
        
        setTimeout(() => {
            ReactDOM.unstable_batchedUpdates(() => {
                this.setState({x: 4})
                this.setState({x: 5})
                this.setState({x: 6})
            })
        }, 0)
    }    
    
    render() {
        return (
} }

這個(gè)API,不用解釋太多,我們看一下它的偽碼就很清楚了

function unstable_batchedUpdates(fn) {
    this.canMerge = true
    
    fn()
    
    this.canMerge = false
    const finalState = ...  //通過(guò)this.updateQueue合并出finalState
    this.setState(finaleState)
}

so, unstable_batchedUpdates 里面的setState也是會(huì)合并的。

forceUpdate的說(shuō)明

forceUpdate從函數(shù)名上理解:“強(qiáng)制更新”。 既然是“強(qiáng)制更新”有兩個(gè)問(wèn)題容易引起誤解:

forceUpdate 是同步的嗎?“強(qiáng)制”會(huì)保證調(diào)用然后直接dom-diff嗎?

“強(qiáng)制”更新整個(gè)組件樹(shù)嗎?包括自己,子孫后代組件嗎?

這兩個(gè)問(wèn)題官方文檔都沒(méi)有明確說(shuō)明。

class A extends React.Component{
    
    handleClick = () => {
        this.forceUpdate()
        this.forceUpdate()
        this.forceUpdate()
        this.forceUpdate()
    }
    
    shouldComponentUpdate() {
        return false
    }
    
    render() {
        return (
            
// 一個(gè)組件
) } }

對(duì)于第一個(gè)問(wèn)題:forceUpdate在批量與否的表現(xiàn)上,和setState是一樣的。在React有控制權(quán)的函數(shù)里,是批量的。

對(duì)于第二個(gè)問(wèn)題:forceUpdate只會(huì)強(qiáng)制本身組件的更新,即不調(diào)用“shouldComponentUpdate”直接更新,對(duì)于子孫后代組件還是要調(diào)用自己的“shouldComponentUpdate”來(lái)決定的。

所以forceUpdate 可以簡(jiǎn)單的理解為 this.setState({}),只不過(guò)這個(gè)setState 是不調(diào)用自己的“shouldComponentUpdate”聲明周期的。

Fiber 的想象

顯示的讓開(kāi)發(fā)者調(diào)用unstable_batchedUpdates是不優(yōu)雅的,開(kāi)發(fā)者不應(yīng)該被框架的實(shí)現(xiàn)細(xì)節(jié)影響。但是正如前文所說(shuō),React沒(méi)有控制權(quán)的函數(shù),unstable_batchedUpdates好像是不可避免的。 不過(guò) React16.xfiber架構(gòu),可能有所改變。我們看下fiber下的更新

setState(newState){
    this.updateQueue.push(newState)
    requestIdleCallback(performWork)
}

requestIdleCallback 會(huì)在瀏覽器空閑時(shí)期調(diào)用函數(shù),是一個(gè)低優(yōu)先級(jí)的函數(shù)。

現(xiàn)在我們?cè)倏紤]一下:

handleClick = () => {
        this.setState({x: 1})
        this.setState({x: 2})
        this.setState({x: 3})
        
        setTimeout(() => {
            this.setState({x: 4})
            this.setState({x: 5})
            this.setState({x: 6})
        }, 0)
    }    

當(dāng)x為1,2,3,4,5,6時(shí) 都會(huì)進(jìn)入更新隊(duì)列,而當(dāng)瀏覽器空閑的時(shí)候requestIdleCallback會(huì)負(fù)責(zé)來(lái)執(zhí)行統(tǒng)一的更新。

由于fiber的調(diào)度比較復(fù)雜,這里只是簡(jiǎn)單的說(shuō)明,具體能不能合并,跟優(yōu)先級(jí)還有其他都有關(guān)系。不過(guò)fiber的架構(gòu)的確可以更加優(yōu)雅的實(shí)現(xiàn)批量更新,而且不需要開(kāi)發(fā)者顯示的調(diào)用unstable_batchedUpdates

廣告時(shí)間

最后,廣告一下我們開(kāi)源的RN轉(zhuǎn)小程序引擎alita,alita區(qū)別于現(xiàn)有的社區(qū)編譯時(shí)方案,采用的是運(yùn)行時(shí)處理JSX的方式,詳見(jiàn)這篇文章。

所以alita內(nèi)置了一個(gè)mini-react,這個(gè)mini-react同樣提供了合成setState/forceUpdate更新的功能,并對(duì)外提供了unstable_batchedUpdates接口。如果你讀react源碼無(wú)從下手,可以看一下alita minil-react的實(shí)現(xiàn),這是一個(gè)適配小程序的react實(shí)現(xiàn), 且小,代碼在https://github.com/areslabs/alita/tree/master/packages/wx-react。

alita地址:https://github.com/areslabs/alita。 歡迎star & pr & issue

文章版權(quán)歸作者所有,未經(jīng)允許請(qǐng)勿轉(zhuǎn)載,若此文章存在違規(guī)行為,您可以聯(lián)系管理員刪除。

轉(zhuǎn)載請(qǐng)注明本文地址:http://systransis.cn/yun/105505.html

相關(guān)文章

  • 精讀《react-easy-state 源碼》

    摘要:會(huì)自動(dòng)觸發(fā)函數(shù)內(nèi)回調(diào)函數(shù)的執(zhí)行。因此利用并將依賴置為使代碼在所有渲染周期內(nèi),只在初始化執(zhí)行一次。同時(shí)代碼里還對(duì)等公共方法進(jìn)行了包裝,讓這些回調(diào)函數(shù)中自帶效果。前端精讀幫你篩選靠譜的內(nèi)容。 1. 引言 react-easy-state 是個(gè)比較有趣的庫(kù),利用 Proxy 創(chuàng)建了一個(gè)非常易用的全局?jǐn)?shù)據(jù)流管理方式。 import React from react; import { stor...

    curlyCheng 評(píng)論0 收藏0
  • 關(guān)于React中的setState

    摘要:而在第二個(gè)參數(shù)中我們輸出了改變后的即第五行輸出,表明我們的更改生效了。而在的回調(diào)內(nèi),我們還調(diào)用了一個(gè)定義于內(nèi)的事件函數(shù),但是該事件函數(shù)內(nèi)的也是同步的形式。 在react中,setState是用以改變class組件狀態(tài)的函數(shù),它有兩種用法:一 傳入一個(gè)updater函數(shù),該函數(shù)有兩個(gè)參數(shù),一個(gè)是當(dāng)前的state,還有一個(gè)是當(dāng)前的props。該函數(shù)的返回值需要是一個(gè)更改的state值的對(duì)象...

    qieangel2013 評(píng)論0 收藏0
  • React Redux: 文檔源碼 - Components篇

    摘要:的作用在文檔中是這么說(shuō)的給下級(jí)組件中的提供可用的的對(duì)象。這個(gè)文件里的主要是被方法引入,并傳給的,算是一個(gè)默認(rèn)的。表示當(dāng)前的名稱。這個(gè)值表示在里面的值。便于控制,同時(shí)某些不需要渲染的,也不會(huì)造成渲染。 注:這篇文章只是講解React Redux這一層,并不包含Redux部分。Redux有計(jì)劃去學(xué)習(xí),等以后學(xué)習(xí)了Redux源碼以后再做分析注:代碼基于現(xiàn)在(2016.12.29)React ...

    alphahans 評(píng)論0 收藏0
  • react: 組件初識(shí) && 生命周期 && 相關(guān)說(shuō)明

    react組件 參考:https://facebook.github.io/re... react的組件是其核心思想部分,react允許將整個(gè)ui設(shè)計(jì)分割稱為獨(dú)立的、可復(fù)用的隔離模塊,react的組件是一個(gè)抽象的類,直接使用reacy.component是沒(méi)有很大意義的,所以一般使用的方法就是定義一個(gè) class 來(lái)繼承這個(gè)component,并且需要實(shí)現(xiàn)方法 render();就像下面一樣: ...

    jokester 評(píng)論0 收藏0
  • react:組件初識(shí) && 生命周期 && tips

    react組件 參考:https://facebook.github.io/re... react的組件是其核心思想部分,react允許將整個(gè)ui設(shè)計(jì)分割稱為獨(dú)立的、可復(fù)用的隔離模塊,react的組件是一個(gè)抽象的類,直接使用reacy.component是沒(méi)有很大意義的,所以一般使用的方法就是定義一個(gè) class 來(lái)繼承這個(gè)component,并且需要實(shí)現(xiàn)方法 render();就像下面一樣: ...

    miqt 評(píng)論0 收藏0

發(fā)表評(píng)論

0條評(píng)論

最新活動(dòng)
閱讀需要支付1元查看
<