why MobX贸街?
React是一個(gè)view層的解決方案沼琉,當(dāng)我們只用它來展示一些靜態(tài)數(shù)據(jù)時(shí)娃承,無需引入任何一種狀態(tài)管理庫奏夫。
當(dāng)多個(gè)有狀態(tài)組件進(jìn)行復(fù)雜的交互時(shí),如果不引入狀態(tài)管理插件历筝,只用state
來實(shí)現(xiàn)酗昼,組件間的狀態(tài)交互將使代碼異常復(fù)雜,業(yè)務(wù)數(shù)據(jù)和UI交互耦合梳猪,難以閱讀麻削。
業(yè)界比較流行的狀態(tài)管理庫是redux,但是redux難以上手春弥,學(xué)習(xí)難度較高呛哟,不適合前端玩票選手。
相比之下匿沛,MobX是一個(gè)異常簡(jiǎn)單且可擴(kuò)展性高的狀態(tài)管理庫扫责,上手簡(jiǎn)單,功能強(qiáng)大逃呼,適合中小型系統(tǒng)鳖孤。
準(zhǔn)備工作
npm install mobx --save
npm install mobx-react --save
tsconfig.json中增加"experimentalDecorators": true
第一個(gè)demo
import * as React from 'react';
import * as ReactDom from 'react-dom';
import { observer } from 'mobx-react';
import { observable, useStrict, action, runInAction, computed } from 'mobx';
// 啟用mobx嚴(yán)格模式,嚴(yán)格模式下不允許直接修改@observable修飾的數(shù)據(jù)抡笼,需@action修飾的方法來修改苏揣。原則上必須用嚴(yán)格模式。
useStrict(true);
class Store {
@observable title:string = '請(qǐng)點(diǎn)擊我推姻!';
@action changeTitle() {
this.title = '已經(jīng)點(diǎn)擊了平匈!';
}
}
const store = new Store();
@observer
class TitlePanel extends React.Component<{},{}> {
render() {
return(<h1 onClick={() => store.changeTitle()}>{store.title}</h1>);
}
}
ReactDom.render(<TitlePanel /> ,document.body);
這里用了三個(gè)陌生的注解,@observable
修飾的數(shù)據(jù)和@observer
修飾的組件綁定拾碌,當(dāng)數(shù)據(jù)發(fā)生變化時(shí)吐葱,組件對(duì)應(yīng)變化。@action
修飾的方法用來改變數(shù)據(jù)校翔。非常簡(jiǎn)單易懂弟跑。
如果不用mobx,這個(gè)demo是這樣的:
class TitlePanels extends React.Component<{}, {}> {
public state = { title: '請(qǐng)點(diǎn)擊我' };
constructor() {
super();
this.onChange = this.onChange.bind(this);
}
onChange() {
this.setState({ title: '已經(jīng)點(diǎn)擊了防症!' });
}
render() {
return (<h1 onClick={this.onChange}>{this.state.title}</h1>);
}
}
看起來好像沒什么區(qū)別孟辑,不使用mobx代碼量還少一點(diǎn)哎甲。所以當(dāng)只維護(hù)一個(gè)有狀態(tài)組件時(shí),無需使用mobx饲嗽。
但是當(dāng)多個(gè)子父組件聯(lián)動(dòng)時(shí)炭玫,使用了mobx,只需在store
中維護(hù)一份數(shù)據(jù)貌虾,即可控制多個(gè)組件的狀態(tài)吞加,大大簡(jiǎn)化組件間交互的邏輯,這也是mobx的價(jià)值所在尽狠。
runInAction
@action
只能影響正在運(yùn)行的函數(shù)衔憨,而無法影響當(dāng)前函數(shù)調(diào)用的異步操作。
所以當(dāng)@action
中有異步請(qǐng)求時(shí)袄膏,需要用runInAction()
包裹践图。調(diào)用后,這個(gè)action方法會(huì)立刻執(zhí)行沉馆。不用runInAction()
码党,異步方法運(yùn)行時(shí)會(huì)報(bào)錯(cuò)。
還是第一個(gè)demo斥黑,當(dāng)要改變的數(shù)據(jù)是從后臺(tái)請(qǐng)求到時(shí):
@action changeTitle() {
post('post/getTitle', res => {
runInAction(() => {
//res.title='已經(jīng)點(diǎn)擊了揖盘!'
this.title = res.title;
});
});
}
computed——計(jì)算屬性
直接上demo:
useStrict(true);
class Store {
@observable goods: any = { price: 20, number: 100 };
@computed get total() {
return this.goods.price * this.goods.number;
}
@action changePrice() {
this.goods.price = Math.floor(Math.random() * 100);
}
}
const store = new Store();
@observer
class TitlePanel extends React.Component<{}, {}> {
render() {
return (<div>
<h1>{`單價(jià):${store.goods.price},數(shù)量:${store.goods.number},總價(jià)${store.total}`}</h1>
<button onClick={() => { store.changePrice() }}>{'點(diǎn)擊改變單價(jià)'}</button>
</div>);
}
}
ReactDom.render(<TitlePanel />, document.body);
@computed
修飾的方法一般用來做計(jì)算/單位轉(zhuǎn)換/格式轉(zhuǎn)換等工作。我們當(dāng)然可以用@aciton
或者直接在render()
中計(jì)算锌奴。
@computed
的優(yōu)點(diǎn)是可以緩存計(jì)算后的值扣讼,提升效率。像demo里這種每次都是不同值缨叫,用@computed
沒有優(yōu)勢(shì)。
@observable
修飾數(shù)組
@observable
可以修飾任何js類型荔燎,包括string耻姥、number、object有咨、array琐簇。
修飾array時(shí)會(huì)有一些需要注意的地方,請(qǐng)看demo座享。