標籤:

redux和react虛擬dom的關係?

provider將store/state和app綁定,每次dispatch都會引起render不過因為虛擬dom的存在,通過diff演算法比較的差異才會修改真實的dom,是我這麼理解的嗎?

——修改一下問題

十分感謝@魯小夫 。另外根據回答,想問的是mapstatetoprops和shouldcomponentupdate的關係是不是只要connect的組件都是對rootstate的監聽,不過shold……里只去關心mapstate……的欄位


謝邀。

redux 跟 virtual dom 沒有關係。

「provider將store/state和app綁定」

錯。

provider 將 store 綁定在 context 上。

connect() 和mapStateToProps()/mapDispatchToProps() 則是組件調用 context 上的 store 的標準方法。

「每次dispatch都會引起render」

錯。每次 dispatch 都會調用 reducer ,然後 shouldComponentUpdate() ,但不一定能走到 render() 。


一點關係都沒有。

似乎題主用了react-redux這個庫,這個庫只是react和redux的橋樑,connect函數產生了一個新的HOC函數,這個新的HoC函數把一個React組件包了一個新的React容器組件,這個新的容器組件實現了shouldComponentUpdate,避免了大量重複渲染。


先說結論,redux和react dom沒有直接關係。

畫了幾張圖幫助理解一下。我們先不看Redux,一個標準的React組件會由以下幾種情況觸發render。

一種是通過setState方法設置了state內容,另一種是外部傳入了props。

當未做任何優化的情況下,只要調用setState 或者 傳入props都會使組件調用render(無論props或者state和原先的內容是否相同)。如果該組件render中包含子組件,那麼子組件也會一同觸發render。(如果是根組件render,那麼整個虛擬dom樹都會被render一次)

當虛擬dom樹render完成後,react會將其和之前的虛擬dom樹進行對比。如果發現有變化,那麼就會改變對應的實際dom節點。如果沒有,則不做改動。(由於實際的dom操作比較耗時,所以跳過的dom操作也是react渲染性能優勢的原因)

由此,你會想到。如果我只是更新了一個組件,但是不想更新它的子組件呢?這裡就提到了shouldComponentUpdate方法。

它是React組件生命周期中的一個方法,當該組件將要執行render之前被調用。你可以通過重寫這個方法來判斷該組件需不需要調用render。

當該方法return false時,react會跳過該組件的render(它的子組件也就不會調用到render了)。

而react-redux的connect其實是實現一個高階組件,將store中的數據傳遞給被connect的組件。簡單來看就是這個樣子(非源碼,僅作示意用):

connect = (mapStateToProps, ...) =&> {
// ...

return (Component) =&> {
// ...

return class extends React.Component {
render() {
const props = {};
// 通過mapStateToProps填充props
// ...

return &;
}
}
}
}

實際上還是通過react來對虛擬dom進行控制。(此外connect也重寫了shouldComponentUpdate來優化渲染)

每次dispatch通過reducer更新store,然後藉由connect來決定是否需要更新Component的屬性,而內部仍然是props傳遞。

ref: Optimizing Performance


redux和react的虛擬dom沒有關係,readux只是一種設計思想,是前端再寫頁面應用時所使用的一種前端架構,這個架構源於flux而來,避免了flux的複雜性,如果你對flux了解,對這個也會很快學會,&

組件使得組件層級匯總的connect()方法能夠獲得redux store,正常情況下,你的根組件應該嵌套在&中才能使用connect()方法。

react中的虛擬dom是為了讓react更加高效而採用的一種方法,因為我們應用越來越複雜,我們的js代碼要管理頁面dom的更新會很複雜,對於dom的更新我們可以先緩存起來,等到在我們完全修改完成之後再修改到實際的dom中,這就和我們一般dom操作是一樣的,先離線操作,等到完成之後,把所有的修改在實際應用到真實的dom中。

而虛擬dom的演算法還是比較複雜的,一般要經歷以下幾個步驟,js現在內存中構建出這個虛擬dom樹,然後通過虛擬dom構建真正的dom,然後生成新的虛擬dom,比較兩課虛擬dom樹的不同,在真正的dom元素上應用變更。


組件重新渲染只有兩用途徑,一是自身調用setState,二是父組件傳入新的props。但這兩種途徑都不會必然調用render而引起重新渲染,會先經過shouldComponentUpdate進行判斷。而一旦一個組件的shouldComponentUpdate返回true,調用了render,就會對該組件的所有子組件傳入新的props,因此所有子組件都會可能重新渲染(依然決定於每一個子組件shouldComponentUpdate的返回值)。

redux用connect綁定組件後,調用dispatch會根據action修改reducer里相應的state分支(這個state不是組件的state,是redux的state),此時redux會對state的變化進行差異比較(這裡有點類似組件自身的shouldComponentUpdate),如果有變化則會對綁定了對應的redux state分支的組件傳入新的props(如果一個組件綁定的所有redux state分支都沒有變化,則該組件不受任何影響),之後組件內部的變化和普通方式傳入新props的變化是一模一樣的。


推薦閱讀:

redux中所有state都要放在store里嗎?
寫在2017的前端數據層不完全指北
感覺redux寫起來很麻煩,目前有那些其他的狀態管理方案?
MobX vs Redux: Comparing the Opposing Paradigms - React Conf 2017 紀要

TAG:React | Redux |