Mobx 基本入门

Mobx, 一个简单、可扩展的状态管理插件, 可结合React, 小程序使用。

这篇文章主要讲一下mobx的基本使用,并且结合React设计一个简单的store。

下面简单介绍一下在react中使用mobx需要掌握的两个简单的概念。

  1. Observable state(可观察的状态)

Mobx可以让现有的js数据结构(数组,对象)添加可观察功能。
这个功能主要是指,能对数据的各种操作进行监听(例如数组的元素的变化,对象的属性的值的更改。),从而实现现下前端所流行的响应式编程。

  1. Observer (观察者)

mobx-react这个库,提供一个叫observer的功能。它能使react组件变成观察者模式。

在观察者模式下,它具有监测Observable state的功能。
当Observable state发生变化时,观察者会收到信息,然后响应这个变化作出事先定义好的行为。

以react来说,它在收到Observable state发生变化的信息时,它会重新调用render方法,把数据更新到视图上。

下面举一个简单的例子

class Counter extends Component {
  count = 0

  render() {
    return (
      <div>
        Counter: {this.count}
        <Button onClick={this.handleAdd}>+</Button>
        <Button onClick={this.handleDec}>-</Button>
      </div>
    )
  }

  handleAdd = () => {
    this.count++
  }

  handleDec = () => {
    this.count--
  }
}

这是一个简单的计数器的例子。通过实例变量count保存数字,通过handleAdd和handleDec这两个方法可以改变count的值。然后在react组件的render函数里把count这个变量映射到视图上。

咋看一下好像没什么问题,但其实有使用react经验的都知道,在react里更新视图需要state属性和setState方法来配合才有意义。即使是redux这个库,也不过是在组件最顶层管理state,然后把state分发到各个组件来使用。

但是mobx能使上面的这种结构变为可能。

@observer
class Counter extends Component {
  @observable count = 0

  render() {
    return (
      <div>
        Counter: {this.count}
        <Button onClick={this.handleAdd}>+</Button>
        <Button onClick={this.handleDec}>-</Button>
      </div>
    )
  }

  handleAdd = () => {
    this.count++
  }

  handleDec = () => {
    this.count--
  }
}

observable这个方法会让count变成可观察的state。而observer这个方法会使react组件变成观察者。当count发生变化时,身为观察者的react组件会对应这个变化而重新调用render方法来更新视图。

PS

Observable state 和 Observer 是互相独立的。
可观察状态不一定是观察者自身的属性。Observable state可以独立于组件外,单独存在于一个对象里。

创建一个给React组件使用的store

下面会以还原真实情景为目标,设计一个存储后台api数据的store。

  1. 为了数据更真实,以下提供一个真实的api地址。

CNode社区api目录,这是node中文社区网站对外开放的一个api目录。CNode的数据主要以帖子为主。以下会选择主题详情这个api来做讲解

这是这个api返回的数据的基本结构

  {
    "success": true,
    "data": {
      "id": "5433d5e4e737cbe96dcef312",
      "author_id": "504c28a2e2b845157708cb61",
      "tab": "share",
      "title": "一个面向 Node.js 初学者的系列课程:node-lessons",
      "last_reply_at": "2016-06-16T08:12:21.234Z",
      "good": true,
      "top": false,
      "reply_count": 85,
      "visit_count": 28422,
      "create_at": "2014-10-07T12:00:36.270Z",
      "is_collect": false,
      "author": {
        "loginname": "alsotang",
        "avatar_url": "https://avatars2.githubusercontent.com/u/1147375?v=3&s=120"
      },
      "replies": []
    }
}
  1. 现在开始设计存储主题详情的store。

    为了让数据结构更清晰,会采用class的形式来构造。
    api返回的数据会以一个实例变量(state)来接受。
    并且state会被构造为Observable state

    class TopicStore {
      @observable state = { 
        isFetching: false,
        isRejected: false,
        isFulfilled: false,
        success: false,
        data: {
          // "id": "5433d5e4e737cbe96dcef312",
          // "author_id": "504c28a2e2b845157708cb61",
          // "tab": "share",
          // "title": "一个面向 Node.js 初学者的系列课程:node-lessons",
          // ........
        }
      }
    }
    

    从上面的例子可以看到,state除了保存了api的返回结果以外,还具有3个bool属性来表示状态。

    • isFetching 用于存储api请求的状态。
    • isRejected 用于表示错误状态。
    • isFulfilled 用于表达数据充满后的状态。

    定义了存储数据的结构后,还需要一个获取数据的方法。

    class TopicStore {
      @observable state = { 
        isFetching: false,
        isRejected: false,
        isFulfilled: false,
        success: false,
        data: {
          // "id": "5433d5e4e737cbe96dcef312",
          // "author_id": "504c28a2e2b845157708cb61",
          // "tab": "share",
          // "title": "一个面向 Node.js 初学者的系列课程:node-lessons",
          // ........
        }
      }
      
      // 这是一个请求主题详情的方法
      fetchTopic(id) {
        // 在api请求前,先需要保存请求的状态(把状态置为请求中)
        this.state.isFetching = true
        
        // 然后发请求
        fetch(...)
          .then(res => {
             // 在这里处理成功后的状态。
             // 假设res就是api返回的数据,数据格式参考上面。
             // 把返回的数据合并到state上
             Object.assign(this.state, res)
             
             // 然后还需要把状态置为请求成功。
             this.state.isFetching = false
             this.state.isFulfilled = true
             
             //上面可以简写成
             Object.assign(this.state, res, {
               isFetching: false,
               isFulfilled: true
             })
          })
          .catch(
            // 错误处理。这里不做介绍。
          )
      }
    }   
    

    最后创建store的实例,以供react组件使用。

    export const topicStore = new TopicStore()
    
  2. 最后需要创建一个react组件来展示主题详情的数据。

import { topicStore } // 导入store实例

@observer //observer让组件变成观察者模式
export default class TopicPage extends Component {
  componentDidMount() {
    // 在组件的生命周期内获取数据。
    topicStore.fetch()    
  }
  
  render() {
    // 在render里使用store里的数据。
    const { id, title, tab, ...data } = topicStore.state.data
    
    renturn ...
  }
}

至此,一个简单的Store就构造完成了。

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 204,590评论 6 478
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 86,808评论 2 381
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 151,151评论 0 337
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 54,779评论 1 277
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 63,773评论 5 367
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 48,656评论 1 281
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 38,022评论 3 398
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 36,678评论 0 258
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 41,038评论 1 299
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 35,659评论 2 321
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 37,756评论 1 330
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 33,411评论 4 321
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 39,005评论 3 307
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 29,973评论 0 19
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 31,203评论 1 260
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 45,053评论 2 350
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 42,495评论 2 343

推荐阅读更多精彩内容

  • Mobx是一个功能强大,上手非常容易的状态管理工具。就连redux的作者也曾经向大家推荐过它,在不少情况下你的确可...
    绯色流火阅读 121,508评论 51 170
  • Android 自定义View的各种姿势1 Activity的显示之ViewRootImpl详解 Activity...
    passiontim阅读 171,439评论 25 707
  • Spring Cloud为开发人员提供了快速构建分布式系统中一些常见模式的工具(例如配置管理,服务发现,断路器,智...
    卡卡罗2017阅读 134,596评论 18 139
  • 一个偶然的时候,发现了北大最帅双胞胎,看了他们的励志减肥故事,真是好有启发,更是让灰色心情的我一下子变成了明媚阳光...
    帅气的小不点阅读 170评论 0 0
  • JavaScript内置函数random(seed)可以产生[0,1)之间的随机数,若想要生成其它范围的随机数该如...
    雪飞鸿阅读 600评论 2 1