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

資訊專欄INFORMATION COLUMN

我為什么從Redux遷移到了Mobx

DevYK / 2548人閱讀

摘要:需要注意的是,在中,需要把數(shù)據(jù)聲明為。同時(shí)還提供了運(yùn)行時(shí)的類型安全檢查。在利用了,使異步操作可以在一個函數(shù)內(nèi)完成并且可以被追蹤。例如在中,數(shù)組并不是一個,而是一個類的對象,這是為了能監(jiān)聽到數(shù)據(jù)下標(biāo)的賦值。

Redux是一個數(shù)據(jù)管理層,被廣泛用于管理復(fù)雜應(yīng)用的數(shù)據(jù)。但是實(shí)際使用中,Redux的表現(xiàn)差強(qiáng)人意,可以說是不好用。而同時(shí),社區(qū)也出現(xiàn)了一些數(shù)據(jù)管理的方案,Mobx就是其中之一。

Redux的問題

Predictable state container for JavaScript apps

這是Redux給自己的定位,但是這其中存在很多問題。
首先,Redux做了什么?看Redux的源碼,createStore只有一個函數(shù),返回4個閉包。dispatch只做了一件事,調(diào)用reducer然后調(diào)用subscribelistener,這其中state的不可變或者是可變?nèi)坑墒褂谜邅砜刂?,Redux并不知道state有沒有發(fā)生變化,更不知道state具體哪里發(fā)生了變化。所以,如果view層需要知道哪一部分需要更新,只能通過臟檢查。

再看react-redux做了什么,在store.subscribe上掛回調(diào),每次發(fā)生subscribe就調(diào)用connect傳進(jìn)去mapStateToPropsmapDispatchToProps,然后臟檢測props的每一項(xiàng)。當(dāng)然,我們可以利用不可變數(shù)據(jù)的特點(diǎn),去減少prop的數(shù)量從而減少臟檢測的次數(shù),但是哪有props都來自同一個子樹這么好的事呢?

所以,如果有n個組件connect,每當(dāng)dispatch一個action的時(shí)候,無論做了什么粒度的更新,都會發(fā)生O(n)時(shí)間復(fù)雜度的臟檢測。

// Redux 3.7.2 createStore.js

// ...
    try {
      isDispatching = true
      currentState = currentReducer(currentState, action)
    } finally {
      isDispatching = false
    }

    const listeners = currentListeners = nextListeners
    for (let i = 0; i < listeners.length; i++) {
      const listener = listeners[i]
      listener()
    }
// ...

更糟糕的是,每次reducer執(zhí)行完Redux就直接調(diào)用listener了,如果在短時(shí)間內(nèi)發(fā)生了多次修改(例如用戶輸入),不可變的開銷,加上redux用字符串匹配action的開銷,臟檢測的開銷,再加上view層的開銷,整個性能表現(xiàn)會非常糟糕,即使在用戶輸入的時(shí)候往往只需要更新一個"input"。應(yīng)用規(guī)模越大,性能表現(xiàn)越糟糕。(這里的應(yīng)用指單個頁面。這里的單頁不是SPA的單頁的意思,因?yàn)橛蠷outer的情況下,被切走的頁面其所有組件都被unmount了)

在應(yīng)用規(guī)模增大的同時(shí),異步請求數(shù)量一多,Redux所宣傳的Predictable也根本就是泡影,更多的時(shí)候是配合各種工具淪為數(shù)據(jù)可視化工具。

Mobx

Mobx可以說是眾多數(shù)據(jù)方案中最完善的一個了。Mobx本身獨(dú)立,不與任何view層框架互相依賴,因此你可以隨意選擇合適的view層框架(部分除外,例如Vue,因?yàn)樗鼈兊脑硎且粯拥模?/p>

目前Mobx(3.x)和Vue(2.x)采用了相同的響應(yīng)式原理,借用Vue文檔的一張圖:

為每個組件創(chuàng)建一個Watcher,在數(shù)據(jù)的getter和setter上加鉤子,當(dāng)組件渲染的時(shí)候(例如,調(diào)用render方法)會觸發(fā)getter,然后把這個組件對應(yīng)的Watcher添加到getter相關(guān)的數(shù)據(jù)的依賴中(例如,一個Set)。當(dāng)setter被觸發(fā)時(shí),就能知道數(shù)據(jù)發(fā)生了變化,然后同時(shí)對應(yīng)的Watcher去重繪組件。

這樣,每個組件所需要的數(shù)據(jù)時(shí)精確可知的,因此當(dāng)數(shù)據(jù)發(fā)生變化時(shí),可以精確地知道哪些組件需要被重繪,數(shù)據(jù)變化時(shí)重繪的過程是O(1)的時(shí)間復(fù)雜度。

需要注意的是,在Mobx中,需要把數(shù)據(jù)聲明為observable。

import React from "react";
import ReactDOM from "react-dom";
import { observable, action } from "mobx";
import { Provider, observer, inject } from "mobx-react";

class CounterModel {
    @observable
    count = 0

    @action
    increase = () => {
        this.count += 1;
    }
}

const counter = new CounterModel();

@inject("counter") @observer
class App extends React.Component {
    render() {
        const { count, increase } = this.props.counter;

        return (
            
{count}
) } } ReactDOM.render( );
性能

在這篇文章中,作者使用了一個一個128*128的繪圖板來說明問題。
由于Mobx利用gettersetter(未來可能會出現(xiàn)一個平行的基于Proxy的版本)去收集組件實(shí)例的數(shù)據(jù)依賴關(guān)系,因此每單當(dāng)一個點(diǎn)發(fā)生更新的時(shí)候,Mobx知道哪些組件需要被更新,決定哪個組件更新的過程的時(shí)間復(fù)雜度是O(1)的,而Redux通過臟檢查每一個connect的組件去得到哪些組件需要更新,有n個組件connect這個過程的時(shí)間復(fù)雜度就是O(n),最終反映到Perf工具上就是JavaScript的執(zhí)行耗時(shí)。

雖然在經(jīng)過一系列優(yōu)化后,Redux的版本可以獲得不輸Mobx版本的性能,當(dāng)時(shí)Mobx不用任何優(yōu)化就可以得到不錯的性能。而Redux最完美的優(yōu)化是為每一個點(diǎn)建立多帶帶的store,這與Mobx等一眾精確定位數(shù)據(jù)依賴的方案在思想上是相同的。

Mobx State Tree

Mobx并不完美。Mobx不要求數(shù)據(jù)在一顆樹上,因此對Mobx進(jìn)行數(shù)據(jù)可是化或者是記錄每次的數(shù)據(jù)變化變得不太容易。在Mobx的基礎(chǔ)上,Mobx State Tree誕生了。同Redux一樣,Mobx State Tree要求數(shù)據(jù)在一顆樹上,這樣對數(shù)據(jù)進(jìn)行可視化和追蹤就變得非常容易,對開發(fā)來說是福音。同時(shí)Mobx State Tree非常容易得到準(zhǔn)確的TypeScript類型定義,這一點(diǎn)Redux不容易做到。同時(shí)還提供了運(yùn)行時(shí)的類型安全檢查。

import React from "react";
import ReactDOM from "react-dom";
import { types } from "mobx-state-tree";
import { Provider, observer, inject } from "mobx-react";

const CountModel = types.model("CountModel", {
    count: types.number
}).actions(self => ({
    increase() {
        self.count += 1;
    }
}));

const store = CountModel.create({
    count: 0
});

@inject(({ store }) => ({ count: store.count, increase: store.increase }))
class App extends React.Component {
    render() {
        const { count, increase } = this.props;

        return (
            
{count}
) } } ReactDOM.render( );

Mobx State Tree還提供了snapshot的功能,因此雖然MST本身的數(shù)據(jù)可變,依然能打到不可變的數(shù)據(jù)的效果。官方提供了利用snaptshot直接結(jié)合Redux的開發(fā)工具使用,方便開發(fā);同時(shí)官方還提供了把MST的數(shù)據(jù)作為一個Redux的store來使用;當(dāng)然,利用snapshot也可以MST嵌在Redux的store中作為數(shù)據(jù)(類似在Redux中很流行的Immutable.js的作用)。

// 連接Redux的開發(fā)工具
// ...
connectReduxDevtools(require("remotedev"), store);
// ...

// 直接作為一個Redux store使用
// ...
import { Provider, connect } from "react-redux";

const store = asReduxStore(store);

@connect(// ...)
function SomeComponent() {
    return Some Component
}

ReactDOM.render(
    
        
    ,
    document.getElementById("foo")
);

// ...

并且,在MST中,可變數(shù)據(jù)和不可變的數(shù)據(jù)(snapshot)可以互相轉(zhuǎn)化,你可以隨時(shí)把snapshot應(yīng)用到數(shù)據(jù)上。

applySnapshot(counter, {
    count: 12345
});

除此之外,官方還提供了異步action的支持。由于JavaScript的限制,異步操作難以被追蹤,即時(shí)使用了async函數(shù),其執(zhí)行過程中也是不能被追蹤的,就會出現(xiàn)雖然在async的函數(shù)內(nèi)操作了數(shù)據(jù),這個async函數(shù)也被標(biāo)記為action,但是會被誤判是在action外修改了數(shù)據(jù)。以往異步action只能通過多個action組合使用來完成,而Vue則是通過把a(bǔ)ction和mutation分開來實(shí)現(xiàn)。在Mobx State Tree利用了Generator,使異步操作可以在一個action函數(shù)內(nèi)完成并且可以被追蹤。

// ...

SomeModel.actions(self => ({
    someAsyncAction: process(function* () {
        const a = 1;
        const b = yield foo(a); // foo必須返回一個Promise
        self.bar = b;
    })
}));

// ...
總結(jié)

Mobx利用gettersetter來收集組件的數(shù)據(jù)依賴關(guān)系,從而在數(shù)據(jù)發(fā)生變化的時(shí)候精確知道哪些組件需要重繪,在界面的規(guī)模變大的時(shí)候,往往會有很多細(xì)粒度更新,雖然響應(yīng)式設(shè)計(jì)會有額外的開銷,在界面規(guī)模大的時(shí)候,這種開銷是遠(yuǎn)比對每一個組件做臟檢查小的,因此在這種情況下Mobx會很容易得到比Redux更好的性能。而在數(shù)據(jù)全部發(fā)生改變時(shí),基于臟檢查的實(shí)現(xiàn)會比Mobx這類響應(yīng)式有更好的性能,但這類情況很少。同時(shí),有些benchmark并不是最佳實(shí)踐,其結(jié)果也不能反映真實(shí)的情況。

但是,由于React本身提供了利用不可變數(shù)據(jù)結(jié)構(gòu)來減少無用渲染的機(jī)制(例如PureComponent,函數(shù)式組件),同時(shí),React的一些生態(tài)和Immutable綁定了(例如Draft.js),因此在配合可變的觀察者模式的數(shù)據(jù)結(jié)構(gòu)時(shí)并不是那么舒服。所以,在遇到性能問題之前,建議還是使用Redux和Immutable.js搭配React。

The real problem is that programmers have spent far too much time worrying about efficiency in the wrong places and at the wrong times; premature optimization is the root of all evil (or at least most of it) in programming.

一些實(shí)踐

由于JavaScript的限制,一些對象不是原生的對象,其他的類型檢查庫可能會導(dǎo)致意想不到的結(jié)果。例如在Mobx中,數(shù)組并不是一個Array,而是一個類Array的對象,這是為了能監(jiān)聽到數(shù)據(jù)下標(biāo)的賦值。相對的,在Vue中數(shù)組是一個Array,但是數(shù)組下標(biāo)賦值要使用splice來進(jìn)行,否則無法被檢測到。

由于Mobx的原理,要做到精確的按需更新,就要在正確的地方觸發(fā)getter,最簡單的辦法就是render要用到的數(shù)據(jù)只在render里解構(gòu)。mobx-react從4.0開始,inject接受的map函數(shù)中的結(jié)構(gòu)也會被追蹤,因此可以直接用類似react-redux的寫法。注意,在4.0之前inject的map函數(shù)不會被追蹤。

響應(yīng)式有額外的開銷,這些開銷在渲染大量數(shù)據(jù)時(shí)會對性能有影響(例如:長列表),因此要合理搭配使用observable.refobservable.shallow(Mobx),types.frozen(Mobx State Tree)。

本文首發(fā)于有贊技術(shù)博客。

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

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

相關(guān)文章

  • 【譯】Redux 還是 Mobx,讓來解決你的困惑!

    摘要:我現(xiàn)在寫的這些是為了解決和這兩個狀態(tài)管理庫之間的困惑。這甚至是危險(xiǎn)的,因?yàn)檫@部分人將無法體驗(yàn)和這些庫所要解決的問題。這肯定是要第一時(shí)間解決的問題。函數(shù)式編程是不斷上升的范式,但對于大部分開發(fā)者來說是新奇的。規(guī)模持續(xù)增長的應(yīng) 原文地址:Redux or MobX: An attempt to dissolve the Confusion 原文作者:rwieruch 我在去年大量的使用...

    txgcwm 評論0 收藏0
  • 前端每周清單半年盤點(diǎn)之 React 與 ReactNative 篇

    摘要:前端每周清單半年盤點(diǎn)之與篇前端每周清單專注前端領(lǐng)域內(nèi)容,以對外文資料的搜集為主,幫助開發(fā)者了解一周前端熱點(diǎn)分為新聞熱點(diǎn)開發(fā)教程工程實(shí)踐深度閱讀開源項(xiàng)目巔峰人生等欄目。與求同存異近日,宣布將的構(gòu)建工具由遷移到,引發(fā)了很多開發(fā)者的討論。 前端每周清單半年盤點(diǎn)之 React 與 ReactNative 篇 前端每周清單專注前端領(lǐng)域內(nèi)容,以對外文資料的搜集為主,幫助開發(fā)者了解一周前端熱點(diǎn);分為...

    Barry_Ng 評論0 收藏0
  • ELSE 技術(shù)周刊(2017.12.04期)

    摘要:版本支持動態(tài),對比九月支持的靜態(tài),動態(tài)會返回請求模塊命名空間的對象以供使用使用開發(fā)瀏覽器插件的過程與收獲初次認(rèn)識是在年阿里的論壇會上,只知道它是運(yùn)行在天生支持跨平臺性的語言,好像很值得關(guān)注。 團(tuán)隊(duì)分享 React 整潔代碼最佳實(shí)踐 作為開發(fā)人員不能僅僅滿足于代碼可以工作,而應(yīng)該讓代碼更易于編寫,閱讀和維護(hù),這篇文章介紹了很多 clean code 在 React 應(yīng)用開發(fā)上的最佳實(shí)踐。...

    Salamander 評論0 收藏0
  • React組件設(shè)計(jì)實(shí)踐總結(jié)05 - 狀態(tài)管理

    摘要:要求通過要求數(shù)據(jù)變更函數(shù)使用裝飾或放在函數(shù)中,目的就是讓狀態(tài)的變更根據(jù)可預(yù)測性單向數(shù)據(jù)流。同一份數(shù)據(jù)需要響應(yīng)到多個視圖,且被多個視圖進(jìn)行變更需要維護(hù)全局狀態(tài),并在他們變動時(shí)響應(yīng)到視圖數(shù)據(jù)流變得復(fù)雜,組件本身已經(jīng)無法駕馭。今天是 520,這是本系列最后一篇文章,主要涵蓋 React 狀態(tài)管理的相關(guān)方案。 前幾篇文章在掘金首發(fā)基本石沉大海, 沒什么閱讀量. 可能是文章篇幅太長了?掘金值太低了? ...

    ideaa 評論0 收藏0
  • Redux 的問題:React、MobX 和 Realm 能解決嗎?

    摘要:它是由一個非常聰明的人開發(fā)的,用來緩解在單頁面應(yīng)用中管理狀態(tài)的問題。的問題沒有一種適合所有場景的完美工具。為設(shè)計(jì)的是世界的另一個新增內(nèi)容,但目前僅適用于。這將導(dǎo)致最后期限延長,并且留下更多需要我們維護(hù)的代碼。 原文:The Problems with Redux: Can React, MobX, and Realm save us? 作者:Erich Reich 首先,我不討厭 ...

    snifes 評論0 收藏0

發(fā)表評論

0條評論

最新活動
閱讀需要支付1元查看
<