摘要:建議將它們用于修改可觀察量或具有副作用的任何函數中。這意味著在一些定時器或者網絡請求,異步處理的情況下,它們的回調函數無法對狀態做成改變。這些回調函數都應該有包裹,如果例子里面的一樣。
1. 介紹 1.1. 原理
React的render是 狀態 轉化為樹狀結構的渲染組件的方法
而MobX提供了一種存儲,更新 狀態 的方法
React 和 MobX都在優化著軟件開發中相同的問題。
React 使用的方法是讓虛擬DOM來減少繁瑣而沉重的DOM變化。
而MobX則通過一個虛擬的狀態依賴圖表來讓react組件和應用狀態同步化來減少不必要的狀態導致組件更新
MobX:
npm install mobx --save
React bindings:
npm install mobx-react --save1.3. 要點
MobX看起來很復雜的樣子,其實是用它只需要三步
定義你的狀態,讓它們成為觀察者(observable)
存儲狀態(Store state)可以是任何的數據結構,隨你定義為:對象,數組,類,循環結構,引用都沒所謂。但需要記住一點,就是:隨著時間的變化,用MobX 去把它們定義成觀察者(observable)
import {observable} from "mobx" let appState = observable({ timer: 0 })
我們不需要讓appState去觀察什么。你現在就能創建視圖(view),每當appState的相關數據發生變化的時候,就會自動更新。MobX會采用最優的方式去更新你的視圖。以下有一個例子來說明如何使用,其中使用了ES6/ES7的語法(當然MobX也是支持ES5),代碼中@的意義
import {observer} from "mobx-react"; @observer class TimerView extends React.Component { render() { return (); } onReset () { //appState.resetTimer會在下一節完成 this.props.appState.resetTimer(); } }; React.render(, document.body);
修改狀態
第三節要說的是修改狀態。MobX和其他框架不同,它不會要求你去做什么事情,它只是幫助你去做簡單的事情
appState.resetTimer = action(function reset() { appState.timer = 0; }); setInterval(action(function tick() { appState.timer += 1; }), 1000);
其中action包裝用法只能在strict模式下使用,請記得在你的javascript文件頭寫上:"use strict"。
2. API從上面的例子可以看到,MobX的API其實不多:observable, computed, reactions, actions
2.1. observable(value)其中的value可以是JS原定的數據結構,引用,對象,數組,ES6的map
如果value是一個map的話,則需要使用一個調節器(modifier)asMap來使用。這時候會返回一個Observable Map
如果是一個數組,返回Observable Array
如果是一個沒有屬性的對象,則返回一個Observable Object
如果是一個有屬性的對象,JS原有的數據結構,函數等,返回一個 Boxed Observable。MobX不會自動讓一個有屬性的對象成為觀察者。這是這個有屬性的對象的構造函數應該做的事情,你可以使用extendObservable在它的構造函數里面,或者在它的類使用@observable去定義。
以下是一些例子:
const map = observable(asMap({ key: "value"})); map.set("key", "new value"); const list = observable([1, 2, 4]); list[2] = 3; const person = observable({ firstName: "Clive Staples", lastName: "Lewis" }); person.firstName = "C.S."; const temperature = observable(20); temperature.set(25);2.2. @observable
import {observable} from "mobx"; class OrderLine { @observable price:number = 0; @observable amount:number = 1; constructor(price) { this.price = price; } //這里在下一節會說到 @computed get total() { return this.price * this.amount; } } const line = new OrderLine(); console.log("price" in line); // true //hasOwnProperty:判斷一個對象是否有你給出名稱的屬性或對象。需要注意,此方法無法檢查該對象的原型鏈中是否具有該屬性 console.log(line.hasOwnProperty("price")); //false
如果你的環境不支持ES6/7的語法的話,其實@observable key = value; 只是extendObservable(this, { key: value })的語法糖。因此在ES5環境下你也能使用
2.3. (@)computedComputed values 就像一個算術公式一樣去從現有的狀態或其他值去計算出需要的值。計算的耗費是不可低估的。Computed盡可能幫你減少其中的耗費。它們是高度優化的,請把它用在可能用到的地方。
不要混淆下一節說到的autorun。雖然他們都是被動調用的表達式。但是……
Computed使用情況:如果你需要產生一個有觀察者(observers)參數計算的新的值的時候
autorun使用情況:你不想產生一個新的值就想達到一個新的效果/功能。就像是打log或者進行網絡請求
Computed values是自動幫你從你的狀態(state)值和其他計算輔助值來計算的。MobX做了很多的優化。當參與計算的值沒有發生改變,Computed是不會重新運行。如果參與計算的值沒有被使用,Computed values是暫停的。
如果Computed values不再是觀察者(observed),那么在UI上也會把它除掉,MobX能自動做垃圾回收。autorun則需要你自己手動去處理。如果參與計算的值不再被使用,是不會緩存Computed的,所以重新計算是需要的。這個是最理想的默認情況。如果你想保留,可以了解一下keepalive和observe。
例子1: 在2.2的例子。@computed get
例子2: @computed set
class Foo { @observable length: 2, @computed get squared() { return this.length * this.length; } set squared(value) { //this is automatically an action, no annotation necessary this.length = Math.sqrt(value); } }
需要注意的是:setter并非用于直接改變參數計算的值,如例子中的length。而是作為一個逆推導。
2.4. AutorunAutorun是用在一些你想要產生一個不用觀察者參與的被動調用函數里面。當autorun被使用的時候,一旦依賴項發生變化,autorun提供的函數就會被執行。與之相反的是,computed提供的函數只會在他有自己的觀察員(observers)的時候才會評估是否重新執行,否則它的值被認為是無用的。
根據這些經驗:如果你需要一個自動運行但卻不會產生任何新的值的結果的函數,那么請使用Autorun。其他情況請使用computed。Autorun只是作用于如果達到某個效果或者功能,而不是計算某些值。如果有一個字符串作為第一個參數存入Autorun,那么它將成為一個調試名稱。
var numbers = observable([1,2,3]); var sum = computed(() => numbers.reduce((a, b) => a + b, 0)); var disposer = autorun(() => console.log(sum.get())); // prints "6" numbers.push(4); // prints "10"2.5. @observer
observer 函數/修飾器用于react組件。通過mobx-react依賴包來提供。它通過mobx.autorun來包裝了組件的render函數,以確保組件的render函數在任何數據的更改是強制重新渲染
import {observer} from "mobx-react"; var timerData = observable({ secondsPassed: 0 }); setInterval(() => { timerData.secondsPassed++; }, 1000); @observer class Timer extends React.Component { render() { return (Seconds passed: { this.props.timerData.secondsPassed } ) } }); React.render(, document.body);
tips: 如果還有其他的decorators一起或者高階組件的存在,請確保observer為最內層(優先應用)的修飾器。否則它可能無法工作。如果你只在ES5的環境下工作:其實observer不過是observer(class Timer ... { }) 的語法糖。
難點—組件中相關值的引用:
MobX能做的事情很多,但是它卻不能把原始的值變成觀察者(盡管可以通過包裹這個值來返回一個boxed observables的對象)。所以觀察者不是這個原始的值,而是返回后的對象的屬性值。修改一個剛才的例子:
React.render(, document.body)
這時候程序并不會工作了。傳入組件的只是timerData里面secondsPassed的當前值。在組件里面,它是不可變的。
把你的組件內部狀態變成可觀察的
和普通的類一樣,你可以在你的組件使用@observable修飾器。這意味著你的組件擁有了一個內部state,而且它不需要使用react內部提供的繁瑣的setState機制。這個內部state能調起render函數,但是卻不能準確調起React的生命周期函數,例如:componentShouldUpdate / componentWillUpdate。如果你想要這些,最好使用react提供的API來創建state。當然也可以這樣寫
import {observer} from "mobx-react" import {observable} from "mobx" @observer class Timer extends React.Component { @observable secondsPassed = 0 componentWillMount() { setInterval(() => { this.secondsPassed++ }, 1000) } render() { return (Seconds passed: { this.secondsPassed } ) } }) React.render(, document.body)
連接observer和stores
mobx-react提供了Provider組件讓你可以把傳遞下來的stores作用在react提供的上下文機制。通過連接這些stores和observer,這些observer會成為組件的屬性來使用。
const colors = observable({ foreground: "#000", background: "#fff" }); const App = () =>; const Button = observer(["colors"], ({ colors, label, onClick }) =>
componentWillReact
React 的組件總是從新的堆棧去渲染。因此讓它它很難判斷一個組件是否需要重新渲染。在mobx-react里面,你可以使用重新定義的生命周期componentWillReact。它只會在觀察者發生變化的時候才重新渲染。
import {observer} from "mobx-react"; @observer class TodoView extends React.Component { componentWillReact() { console.log("I will re-render, since the todo has changed!"); } render() { returnthis.props.todo.title; } }
componentWillReact沒有任何參數,而且不會在render初始化之前執行(componentWillMount的區別)。而當接收新的屬性或者setState之后,它會被調用。
2.6. action任何應用程序都有操作(action)。action是任何改變狀態的事物。使用MobX,您可以通過標記它們在您的代碼中顯式地顯示您的操作(action)。它會更好的幫助你組織你的代碼。建議將它們用于修改可觀察量或具有副作用的任何函數中。
需要注意的是:action是用在strict mode 中的
action(fn) action(name, fn) @action classMethod() {} @action(name) classMethod () {} @action boundClassMethod = (args) => { body } @action(name) boundClassMethod = (args) => { body } @action.bound classMethod() {} @action.bound(function() {})
@action createRandomContact() { this.pendingRequestCount++; superagent .get("https://randomuser.me/api/") .set("Accept", "application/json") .end(action("createRandomContact-callback", (error, results) => { if (error) console.error(error) else { const data = JSON.parse(results.text).results[0]; const contact = new Contact(this, data.dob, data.name, data.login.username, data.picture) contact.addTag("random-user"); this.contacts.push(contact); this.pendingRequestCount--; } } ))}
action 僅僅作用于當前運行的函數,而不能作用于當前函數調用的函數。這意味著在一些定時器或者網絡請求,異步處理的情況下,它們的回調函數無法對狀態做成改變。這些回調函數都應該有action包裹,如果例子里面的 createRandomContact-callback 一樣。但是,如果你使用了async / await的話,最好的方式應該是使用 runInAction 來讓它變得更加簡單
@action /*optional*/ updateDocument = async () => { const data = await fetchDataFromUrl(); /* required in strict mode to be allowed to update state: */ runInAction("update state after fetching data", () => { this.data.replace(data); this.isSaving = true; }) }
Bound actions
目前看到的actions都是遵循在javascript中綁定的正常規則,但是在MobX 3引入了action.bound來自動綁定actions到目標對象上。和action的使用不一樣,不需要一個名字參數。它的名稱始終基于綁定到屬性的操作上。需要注意的是,在箭頭函數上不要這樣使用,因為箭頭函數已經綁定了上下文,不能在重新更改上下文
class Ticker { @observable this.tick = 0 @action.bound increment() { this.tick++ // "this" will always be correct } } const ticker = new Ticker() setInterval(ticker.increment, 1000)后記
啟動例子項目:進入
前端項目:npm install 或者 yarn install 打開本地的8080端口
后端部分:進入 back文件夾,執行npm start 打開本地的3000端口
作為對比:使用redux的例子:進入
文章版權歸作者所有,未經允許請勿轉載,若此文章存在違規行為,您可以聯系管理員刪除。
轉載請注明本文地址:http://specialneedsforspecialkids.com/yun/81421.html
摘要:原理分析的核心就是通過觀察某一個變量,當該變量產生變化時,對應的內的回調函數就會發生變化。回調函數若依賴外部環境,則無法進行收集很好理解,的回調函數在預執行的時候無法到達那一行代碼,所以收集不到。 Mobx解決的問題 傳統React使用的數據管理庫為Redux。Redux要解決的問題是統一數據流,數據流完全可控并可追蹤。要實現該目標,便需要進行相關的約束。Redux由此引出了dispa...
摘要:我現在寫的這些是為了解決和這兩個狀態管理庫之間的困惑。這甚至是危險的,因為這部分人將無法體驗和這些庫所要解決的問題。這肯定是要第一時間解決的問題。函數式編程是不斷上升的范式,但對于大部分開發者來說是新奇的。規模持續增長的應 原文地址:Redux or MobX: An attempt to dissolve the Confusion 原文作者:rwieruch 我在去年大量的使用...
摘要:是一個的簡單可擴展的狀態管理庫。它的副作用是自動更新。該函數返回一個值,當返回值為的時候,才會繼續觸發第一個函數。當返回值為時,不再繼續監聽。包含一個,該值用來區分執行事件的類型。 mobx 能干什么 使用 react 寫小型應用,數據、業務邏輯和視圖的模塊劃分不是很細是沒有問題的。在這個階段,引入任何狀態管理庫,都算是奢侈的。但是隨著頁面邏輯的復雜度提升,在中大型應用中,數據、業務邏...
摘要:關心性能的情況下,需要手動設置這時就需要引入狀態管理庫。現在常用的狀態管理庫有和,本文會重點介紹,然后會將和進行對比,最后展望下未來的狀態管理方面趨勢。如果在任何地方都修改可觀察數據,將導致頁面狀態難以管理。 React 是一個專注于視圖層的庫。React 維護了狀態到視圖的映射關系,開發者只需關心狀態即可,由 React 來操控視圖。 在小型應用中,單獨使用 React 是沒什么問題...
摘要:隨后,執行官給出一張當張三存款發生變化之時,此機構的運作時序圖的確,小機構靠人力運作,大機構才靠制度運轉。第一條語句創建觀察員第一條語句張三我們調用的時候,就創建了對象,對象的所有屬性都將被拷貝至一個克隆對象并將克隆對象轉變成可觀察的。 ================前言=================== 初衷:網上已有很多關于 MobX 源碼解讀的文章,但大多閱讀成本甚高。...
摘要:需要注意的是,在中,需要把數據聲明為。同時還提供了運行時的類型安全檢查。在利用了,使異步操作可以在一個函數內完成并且可以被追蹤。例如在中,數組并不是一個,而是一個類的對象,這是為了能監聽到數據下標的賦值。 Redux是一個數據管理層,被廣泛用于管理復雜應用的數據。但是實際使用中,Redux的表現差強人意,可以說是不好用。而同時,社區也出現了一些數據管理的方案,Mobx就是其中之一。 R...
閱讀 3409·2021-09-22 16:00
閱讀 3452·2021-09-07 10:26
閱讀 2989·2019-08-30 15:55
閱讀 2858·2019-08-30 13:48
閱讀 1366·2019-08-30 12:58
閱讀 2162·2019-08-30 11:15
閱讀 945·2019-08-30 11:08
閱讀 525·2019-08-29 18:41