十分钟快速上手react之mobx、mobx-react

前言

目前React框架越来越火,使用 react 公司越来越多!随着页面逻辑的复杂度提升,各种状态库也层次不穷,业内比较成熟的解决方案有 Redux、但是Redux使用相对繁琐,对于新手来说不友好。所以今天特意推荐大家可以去尝试使用另一个比较成熟的状态管理工具Mobx,mobx 的核心理念是 简单、可扩展的状态管理库。

个人感觉它和vuex有很多相似之处,如果你会vuex十分钟就可以搞定。

Mobx它通过透明的函数响应式编程(transparently applying functional reactive programming - TFRP)使得状态管理变得简单和可扩展。

准备工作

可以使用create-react-app构建一个react项目,也可以看我之前写的webapck小白成神之路文章手动搭建一套react项目(个人推荐第二种,手动搭建会学到很多知识点)

环境配置

安装mobx mobx-react

  npm install --save mobx mobx-react

因为要用到装饰器,所以需要安装一个依赖去解析

  npm i --save-dev babel-plugin-transform-decorators-legacy

然后在.babelrc配置

{
  "presets": ["react", "env", "stage-0"], 
  "plugins": ["transform-runtime", "transform-decorators-legacy"] 
}

observable

仓库

新建test.js

import {observable} from 'mobx';

class TestStore {
    // 被观察者
    @observable name; 
    constructor() {
        this.name = '浮云先生'
    }
}
const test = new TestStore() 
export default test

可以看到我们在数据仓库中写入name = "浮云先生",

observer

组件

import React from 'react'
import ReactDOM from 'react-dom'
import {observer, inject} from 'mobx-react';

// 观察者
@inject('test') 
@observer
class DemoComponent extends React.Component {
    constructor(props) {
        super(props);
    }

    render() {
        const { test } = this.props;
        return (
            <div>
                <p>{test.name}</p>
            </div>
        );
    }
}

export default DemoComponent;

  • inject 在模块内用 @inject('Store'),将 Store 注入到 props 上,保证结构的一致性
    使用 @observer ,将组件变为观察者,响应 name 状态变化。
    当状态变化时,组件也会做相应的更新。

computed

有时候,state 并不一定是我们需要的最终数据。例如,所有的 todo 都放在 store.todos 中,而已经完成的 todos 的值(store.unfinishedTodos),可以由 store.todos 衍生而来。

对此,mobx 提供了 computed 装饰器,用于获取由基础 state 衍生出来的值。如果基础值没有变,获取衍生值时就会走缓存,这样就不会引起虚拟 DOM 的重新渲染。

通过 @computed + getter 函数来定义衍生值(computed values)。

import { computed } from 'mobx';

class Store {
  @observable todos = [{
    title: "todo标题",
    done: false,
  },{
    title: "已经完成 todo 的标题",
    done: true,
  }];

  @computed get finishedTodos () {
    return  this.todos.filter((todo) => todo.done)
  }
}

这样组建中就可以直接拿到finishedTodos 过滤后的值了

action

首先在 Store 中,定义action(动作)(test.js)

import {observable, action} from 'mobx';

class TestStore {
    @observable name; 
    // 定义action(动作)
    @action 
    changeName = name => {
        this.name = name
    }

    constructor() {
        this.name = '浮云先生'
    }
}
const test = new TestStore() 
export default test

在组件中只需要this.props.test.changeName ('改变')调用就可以。是不是很简单~

异步请求

方式1:runInAction/async/await

import {observable, action} from 'mobx';
class MyState {
    @observable data = null;
    @observable state = null;
    @action initData = async () => {
        try {
            const data = await getData("xxx");
            runInAction("说明一下这个action是干什么的。不写也可以", () => {
                this.state = "success"
                this.data = data;
            })
        } catch (error) {
            runInAction(() => {
                this.state = "error"
            })
        }
        
    };
}

方式2:flows

更好的方式是使用 flow 的内置概念。它们使用生成器。一开始可能看起来很不适应,但它的工作原理与 async / await 是一样的。只是使用 function * 来代替 async,使用 yield 代替 await 。 使用 flow 的优点是它在语法上基本与 async / await 是相同的 (只是关键字不同),并且不需要手动用 @action 来包装异步代码,这样代码更简洁。

class Store {
    @observable data = null;
    @observable state = null;

    fetchProjects = flow(function * () { // <- 注意*号,这是生成器函数!
        try {
            const projects = yield getData() // 用 yield 代替 await
            // 异步代码块会被自动包装成动作并修改状态
            this.state = "success"
            this.data = projects
        } catch (error) {
            this.state = "error"
        }
    })
}

大型项目中定义多个状态(模块化)

假如我们有两个模块分别是test.js和mast.js
test.js

import {observable, action} from 'mobx';

class TestStore {
    @observable name; 
    @observable age;

    @action 
    changeAge = i => {
        this.age = this.age + Number(i)
    }

    constructor() {
        this.name = '浮云先生'
        this.age = 25
    }
}
const test = new TestStore() 
export default test

mast.js

// 这里引入的是 mobx
import {observable, computed, action} from 'mobx';

class MastSotre {
    @observable list; 

    @computed
    get getList () {
        return this.list.filter(v => v.id !== 1)
    }

    @action
    addList = obj => this.list.push(obj)

    constructor() {
        this.list = [
            {
                name: '香蕉',
                id: 0
            },
            {
                name: '苹果',
                id: 1
            },
            {
                name: '西瓜',
                id: 2
            }
        ]
    }
}
const mast = new MastSotre() 
export default mast

新建index.js进行汇总

// 汇总store
import test from './test'
import mast from './mast'

const stores = {
    test,
    mast,
}
export default stores

在入口文件中全局注入数据

import React from 'react'  
import ReactDOM from 'react-dom'  
import RouterContainer from './router/index'
import { Provider } from "mobx-react"
import stores from './store'

import {configure} from 'mobx'; // 开启严格模式
configure({enforceActions: true}) // 开启严格模式

ReactDOM.render(
    <Provider {...stores}>
        <RouterContainer/>
    </Provider>,
    document.getElementById('example')
);
  • Provider 通过 Provider 渗透
  • configure 代表开启了严格模式,因为非严格模式下,组件是直接可以通过props.action改变state数据的,当项目复杂的时候这样是非常危险的。所以要设置唯一改变state方式是通过action

简单的对常用的知识点进行了汇总,同学们看了后是不是觉得很简单!
想要深入学习的Mobx官网传送门:https://cn.mobx.js.org/

最后

同学你都读到这里了,还不点赞加关注吗?
溜了溜了.................

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

推荐阅读更多精彩内容