Mobx入门之四:自定义reactions,when, autorun

在之前的文章中使用了observer包装App, 实现了页面的动态刷新,这里主要了解一下另外两种reaction的实现:when和autorun

 

When

when(predicate: () => boolean, effect?: () => void, options?)

when 观察并运行给定的 predicate,直到返回true。 一旦返回 true,给定的 effect 就会被执行,然后 autorunner(自动运行程序) 会被清理。 该函数返回一个清理器以提前取消自动运行程序。

也就是说,when的使用可以传入有前置条件

 

下面的例子使用when实现在温度>25的时候,会alert出这个城市的名字

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)
  }
)

 

autorun

当你想创建一个响应式函数,而该函数本身永远不会有观察者时,可以使用 mobx.autorun

当使用 autorun时,所提供的函数总是立即被触发一次,然后每次它的依赖关系改变时会再次被触发。

 经验法则:如果你有一个函数应该自动运行,但不会产生一个新的值,请使用autorun。 其余情况都应该使用 computed

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来更新UI

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)
})

 

转载于:https://my.oschina.net/u/2510955/blog/1836023

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值