在以前的文章中使用了observer包裝App, 實現了頁面的動態刷新,這裏主要了解一下另外兩種reaction的實現:when和autorunjavascript
when(predicate: () => boolean, effect?: () => void, options?)
when
觀察並運行給定的 predicate
,直到返回true。 一旦返回 true,給定的 effect
就會被執行,而後 autorunner(自動運行程序) 會被清理。 該函數返回一個清理器以提早取消自動運行程序。java
也就是說,when的使用能夠傳入有前置條件react
下面的例子使用when實如今溫度>25的時候,會alert出這個城市的名字json
import ReactDOM from 'react-dom' import React from 'react' import { action, computed, observable, when } from 'mobx' import { Provider, observer, inject } from 'mobx-react' import DevTools from 'mobx-react-devtools' const APPID = '415a88f2b45f08c3e561b058772ec6c3' class Temperature { id = Math.random() @observable unit = 'C' @observable temperatureCelsius = 25 @observable location = 'Amsterdam, NL' @observable loading = true constructor (location) { this.location = location this.fetch() } @computed get temperatureKelvin () { console.log('calculating Kelvin') return this.temperatureCelsius * (9 / 5) + 32 } @computed get temperatureFahrenheit () { console.log('calculating Fahrenheit') return this.temperatureCelsius + 273.15 } @computed get temperature () { console.log('calculating temperature') switch (this.unit) { case 'K': return this.temperatureKelvin + '°K' case 'F': return this.temperatureFahrenheit + '°F' case 'C': return this.temperatureCelsius + '°C' default: return this.temperatureCelsius + '°C' } } @action fetch () { window.fetch(`http://api.openweathermap.org/data/2.5/weather?appid=${APPID}&q=${this.location}`) .then(res => res.json()) .then(action(json => { this.temperatureCelsius = json.main.temp - 273.15 this.loading = false })) } @action setUnit (newUnit) { this.unit = newUnit } @action setCelsius (degrees) { this.temperatureCelsius = degrees } @action('update temperature and unit') setTemperatureAndUnit (degrees, unit) { this.setUnit(unit) this.setCelsius(degrees) } @action inc() { this.setCelsius(this.temperatureCelsius + 1) } } @inject('temperatures') @observer class TemperatureInput extends React.Component { @observable input = '' render () { return ( <li> Destination <input value={this.input} onChange={this.onChange}/> <button onClick={this.onSubmit}>Add</button> </li> ) } @action onChange = e => { this.input = e.target.value } @action onSubmit = () => { this.props.temperatures.push(new Temperature(this.input)) this.input = '' } } @observer class TView extends React.Component { render () { const t = this.props.temperature return ( <li key={t.id} onClick={() => this.onTemperatureClick()}>{t.location}: {t.loading ? 'loading...' : t.temperature}</li> ) } @action onTemperatureClick = () => { this.props.temperature.inc() } } const App = inject('temperatures')(observer( ({ temperatures }) => ( <ul> <TemperatureInput /> {temperatures.map(t => <TView key={t.id} temperature={t} /> )} <DevTools/> </ul> ))) const temps = observable([]) ReactDOM.render( <Provider temperatures={temps}> <App /> </Provider>, document.getElementById('root') ) /* 判斷溫度是否適宜 */ function isNice (t) { return t.temperatureCelsius > 25 } // 若是temps中有溫度>25的, 就執行第二個函數,找到第一個適宜的溫度(> 25), alert when( () => temps.some(isNice), () => { const t = temps.find(isNice) alert('Book now! ', t.location) } )
當你想建立一個響應式函數,而該函數自己永遠不會有觀察者時,能夠使用 mobx.autorun
api
當使用 autorun
時,所提供的函數老是當即被觸發一次,而後每次它的依賴關係改變時會再次被觸發。app
經驗法則:若是你有一個函數應該自動運行,但不會產生一個新的值,請使用autorun
。 其他狀況都應該使用 computed
dom
var numbers = observable([1,2,3]); var sum = computed(() => numbers.reduce((a, b) => a + b, 0)); var disposer = autorun(() => console.log(sum.get())); // 輸出 '6' numbers.push(4); // 輸出 '10' disposer(); numbers.push(5); // 不會再輸出任何值。`sum` 不會再從新計算。
咱們的某個地方得到天氣的例子,使用autorun來更新UIide
import { action, computed, observable, when, autorun } from 'mobx' const APPID = '415a88f2b45f08c3e561b058772ec6c3' class Temperature { id = Math.random() @observable unit = 'C' @observable temperatureCelsius = 25 @observable location = 'Amsterdam, NL' @observable loading = true constructor (location) { this.location = location this.fetch() } @computed get temperatureKelvin () { console.log('calculating Kelvin') return this.temperatureCelsius * (9 / 5) + 32 } @computed get temperatureFahrenheit () { console.log('calculating Fahrenheit') return this.temperatureCelsius + 273.15 } @computed get temperature () { console.log('calculating temperature') switch (this.unit) { case 'K': return this.temperatureKelvin + '°K' case 'F': return this.temperatureFahrenheit + '°F' case 'C': return this.temperatureCelsius + '°C' default: return this.temperatureCelsius + '°C' } } @action fetch () { window.fetch(`http://api.openweathermap.org/data/2.5/weather?appid=${APPID}&q=${this.location}`) .then(res => res.json()) .then(action(json => { this.temperatureCelsius = json.main.temp - 273.15 this.loading = false })) } @action setUnit (newUnit) { this.unit = newUnit } @action setCelsius (degrees) { this.temperatureCelsius = degrees } @action('update temperature and unit') setTemperatureAndUnit (degrees, unit) { this.setUnit(unit) this.setCelsius(degrees) } @action inc () { this.setCelsius(this.temperatureCelsius + 1) } } const temps = observable([]) /* 判斷溫度是否適宜 */ function isNice (t) { return t.temperatureCelsius > 25 } function render (temperatures) { return ` <ul> ${temperatures.map(t => `<li> ${t.location}: ${t.loading ? 'loading' : t.temperature} </li> ` ).join('')} </ul> ` } temps.push(new Temperature('Amsterdam')) temps.push(new Temperature('Rotterdam')) when( () => temps.some(isNice), () => { const t = temps.find(isNice) alert('Book now! ', t.location) } ) autorun(() => { document.getElementById('app').innerHTML = render(temps) })