• 一:主要介绍一下mobx-react mobx-react的优点: 用mobxmobx-react代替redux和react-redux已经时大势所趋,既解决越写越零散的reducer,又解决了跨组件引入状态管理的问题。 复制代码 1、安装,这里有两个包需要...

    一:主要介绍一下mobx-react

    mobx-react的优点:

    用mobx和mobx-react代替redux和react-redux已经时大势所趋,既解决越写越零散的reducer,又解决了跨组件引入状态管理的问题。
    复制代码

    1、安装,这里有两个包需要安装,mobx 和 mobx-react

    npm i mobx mobx-react --s-d   
    复制代码

    或者

    npm install mobx-react --save
    复制代码

    注意如果要兼容IE必须使用5.x.x或者之前的版本

    2、创建mobx主文件(例子创建的目录是mobx/index.js)

    引入mobx

    class mainStore{
           @observable firstState = 0;
           @action onClick=()=>{
             console.log('触发了action')
         }
    }
    
    export default mainStore;
    复制代码

    3、在任意组件里加入mobx-react并使用

    import React from 'react';
    import { inject , observer } from 'mobx-react';
    
    @inject('store')
    @observer
    class test extends React.Component {
        constructor(props){
            super(props);
            console.log(this.props.store.loginState);
            this.props.store.onClick('login')
        }
    }
    复制代码

    二:从三个方面比较mobx-react 与 redux_react

    主要比较参数:

    库体积,打包项目体积
    
    开发体验
    
    性能对比
    复制代码

    (1)库体积,打包项目体积

    redux比mobx打包体积略大,几乎可以忽略不记,但是lib包比mobx小20k,所以这轮redux胜

    (2)开发体验

    开发效率:由于mobx是双向绑定的,开发的时候你会觉得mobx写的都是有效代码;redux写同一个功能会多写很多代码,代码逻辑绕啊绕。

    代码质量:redux直接写,不做react渲染优化是个大坑,但是react渲染优化又比较繁琐,可能还要添加第三方插件,增加不必要的代码量。mobx基本不做渲染优化,渲染更新,是否更新的生命周期都被禁用了,还优化个屁。

    综上 开发体验上mobx比redux领先太多。

    (3)性能对比

    性能对比 此次比较是redux项目已经优化,mobx项目未优化的情况下进行的,mobx项目优化后会补坑

    Mbox

    Mobx专注于解决数据级别的响应,它不关系数据的来源方式,只要一个对象中的属性、一个基本类型变量发生了变化,对这些数据的订阅就会自动执行。使用Mobx管理状态时,当我们更新观察对象的状态后,由观察对象的改变带来的界面重渲染、数据序列化等一系列副作用,Mobx会自动帮我们完成。

    Mobx的主要概念

    Actions: 改变state的操作。

    ObservableState:应用的可被观察的数据状态。

    Computed: 从state中通过纯函数的操作衍生出的值,state变化它也会跟着变化。

    Reactions:需要对state变化动态作出反应的东西,它包含不同的概念,基于被观察数据的更新导致某个计算值,或者是发送网络请求以及更新视图等,都属于响应的范畴,这也是响应式编程在 JavaScript 中的一个应用。

    Autorun: 依赖收集,监听触发,autorun 背后由 reaction 实现。由于 autorun 与 view 的 render 函数很像,我们在 render 函数初始化执行时,使其包裹在 autorun 环境中,第 2 次 render 开始遍剥离外层的 autorun,保证只绑定一遍数据。这样 view 层在原本 props 更新机制的基础上,增加了 autorun 的功能,实现修改任何数据自动更新对应 view 的效果。(ps:使用autoRun实现Mobx-react非常简单,核心思想是将组件外面包上autoRun,这样代码中用到的所有属性都会像上面Demo一样,与当前组件绑定,一旦任何值发生了修改,就直接forceUpdate,而且精确命中,效率最高。)

    Mobx流程

    (三)Mobx的优缺点

    优点:

    1.使用起来十分顺手,降低开发难度。十分“智能”,当我们更新观察对象的状态后,由观察对象的改变带来的界面重渲染、数据序列化等一系列副作用,Mobx会自动帮我们完成。

    2.面向对象的使用方法,较为符合我们平时开发的逻辑。

    缺点:

    1.无副作用隔离,非严格模式下可以对observable直接修改,这样容易造成 store 被随意修改。在项目规模比较大的时候,像 Vuex 和 Redux 一样对修改数据的入口进行限制可以提高安全性。因此如果不规范Mobx使用的话将会导致数据流变化混乱问题。

    2.在收集依赖时,Mobx会把autorun执行一遍来触发里面observable的getter从而收集依赖。但是万一你写出了以下的代码,Mobx是收集不到你想要收集的依赖的

    3.observable跟普通的plainObject傻傻分不清楚,observable跟plainObject外貌上一摸一样,有时可能会误会了observable的本质

    (四)Mobx与Redux的区别

    1.从数据管理模式的差别上看,Mobx是基于双向绑定的响应式的实现,而redux是基于flux的单向数据流的实现。

    2.从开发上来看是和面向对象和函数式编程的区别。但是前端开发需要经常与副作用打交道,所以前端开发很难与完美的函数式编程相结合。

    3.redux的state是只读的,产生新的state的过程是pure的;Mobx的state可读可写,并且action并不是必须的,可以直接赋值改变,这也看出了Mobx改变数据的impure。

    4.在可预测性、可维护性上看,redux得益于它的清晰的单向数据流和纯函数的实现,在这方面优于Mobx。

    5.redux是单一数据源;而Mobx是多个store。

    6.redux中的store是普通的js对象结构,而Mobx中的会对其进行observable化,从而实现响应式。

    7.从代码量上看,Mobx能少写很多代码,而redux要通过action,reducer等等的编写才能实现整个流程。

    (五)Redux

    Redux 是 JavaScript 状态容器,提供可预测化的状态管理.核心概念就是初始状态通过reduce接收只是一个接收 state 和 action,并返回新的 state,所得的就是当前状态。

    Redux三大原则

    单一数据源 整个应用的 state 被储存在一棵 object tree 中,并且这个 object tree 只存在于唯一一个 store 中。

    State 是只读的 唯一改变 state 的方法就是触发 action,action 是一个用于描述已发生事件的普通对象。

    使用纯函数来执行修改 为了描述 action 如何改变 state tree ,你需要编写 reducers。Reducer 只是一些纯函数,它接收先前的 state 和 action,并返回新的 state。并不做其他操作(修改传入的参数;执行有副作用的操作;调用非纯函数)。

    redux各个组成部分

    Action

    Action 是把数据从应用传到 store 的有效载荷,它是 store 数据的唯一来源。一般来说你会通过 store.dispatch() 将 action 传到 store。

    注意:“action” 和 “action 创建函数” 这两个概念很容易混在一起,使用时最好注意区分。Action 创建函数 就是生成 action 的方法
    复制代码

    Reducer

    actions 只是描述了有事情发生了这一事实,并没有描述应用如何更新 state。而Reducer就是一个纯函数,接收旧的 state 和 action,返回新的 state。 现在只需要谨记 reducer 一定要保持纯净。只要传入参数相同,返回计算得到的下一个 state 就一定相同。没有特殊情况、没有副作用,没有 API 请求、没有变量修改,单纯执行计算。

    Store

    Redux 应用只有一个单一的 store,Store是把action和reducer联系到一起到对象Store 有以下职责:

    1.维持应用的 state; 2.提供 getState() 方法获取 state; 3.提供 dispatch(action) 方法更新 state; 4.通过 subscribe(listener) 注册监听器; 5.通过 subscribe(listener) 返回的函数注销监听器

    Redux流程

    react+redux流程

    Redux优缺点

    优点 1.纯函数的开发模式,无副作用。 2.单向数据流流动自然清晰,任何的dispatch都会通知到reducer来处理,增强更新粒度可控性。 3.利用中间件的模式来解决异步带来的副作用问题。 4.可时间回溯。为了解决阻碍回溯的“对象引用”机制,将 immutable应用到了前端。这下所有状态都不会被修改,基于此的redux-dev-tools提高了开发体验 缺点:

    1.代码书写啰嗦,造成代码冗余

    扩展

    Redux处理异步的中间件

    Redux针对异步数据流的情况,也设计出中间件这个概念来隔离异步所带来的副作用。它的主要目的就是控制异步dispatch,分离副作用。

    接下来说说最具代表性的两个异步中间件:redux-thunk 和 redux-saga。

    redux-thunk

    redux-thunk 的任务执行方式是从 UI 组件直接触发任务,redux-thunk 的主要思想是扩展 action,使得 action 从一个对象变成一个函数。

    redux-saga sages 采用 Generator 函数来 yield Effects(包含指令的文本对象)。Generator 函数的作用是可以暂停执行,再次执行的时候从上次暂停的地方继续执行.在 redux-saga 中,UI 组件自身从来不会触发任务,它们总是会 dispatch 一个 action 来通知在 UI 中哪些地方发生了改变,而不需要对 action 进行修改

    redux-thunk 的缺点:

    (1)action 虽然扩展了,但因此变得复杂,后期可维护性降低; (2)thunks 内部测试逻辑比较困难,需要mock所有的触发函数; (3)协调并发任务比较困难,当自己的 action 调用了别人的 action,别人的 action 发生改动,则需要自己主动修改; (4)业务逻辑会散布在不同的地方:启动的模块,组件以及thunks内部。 redux-saga 的优点: (1)声明式 Effects:所有的操作以JavaScript对象的方式被 yield,并被 middleware 执行。使得在 saga 内部测试变得更加容易,可以通过简单地遍历 Generator 并在 yield 后的成功值上面做一个 deepEqual 测试。 (2)高级的异步控制流以及并发管理:可以使用简单的同步方式描述异步流,并通过 fork 实现并发任务。 (3)架构上的优势:将所有的异步流程控制都移入到了 sagas,UI 组件不用执行业务逻辑,只需 dispatch action 就行,增强组件复用性。

    总结

    优化过后的redux项目性能比较好,mobx暂时还没想到特别好的优化方案,找到了会补坑;框架体验,开发效率,学习成本方面mobx更好,希望优化过后的mobx性能有所提升;代码打包体积redux确实要小点,但是如果项目比较庞大,redux开发代码会比mobx多不少,体积这方面基本可以忽略。

    展开全文
  • 目前React框架越来越火,使用 react 公司越来越多!随着页面逻辑的复杂度提升,各种状态库也层次不穷,业内比较成熟的解决方案有 Redux、但是Redux使用相对繁琐,对于新手来说不友好。所以今天特意推荐大家可以去...

    前言

    目前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/



    作者:抱紧我_8204
    链接:https://www.jianshu.com/p/6a12b3121379
    來源:简书
    简书著作权归作者所有,任何形式的转载都请联系作者获得授权并注明出处。

    展开全文
  • 使用mobx进行状态管理相比于redux显得更加的轻量级,mobx采用响应式编程,主要采用观察者模式,redux使用不开心不妨试试mobx 下面主要说明在项目中使用mobx如何友好组织多个store,以及在view层注入我们想使用的store ...

    使用mobx进行状态管理相比于redux显得更加的轻量级,mobx采用响应式编程,主要采用观察者模式,redux使用不开心不妨试试mobx
    下面主要说明在项目中使用mobx如何友好组织多个store,以及在view层注入我们想使用的store

    store.js

    import {observable} from 'mobx';
    
    class UserStore {
      constructor(rootStore) {
        this.rootStore = rootStore
      }
    
      getTodos(user) {
        // 通过根 store 来访问 todoStore
        return this.rootStore.todoStore.todos.filter(todo => todo.author === user)
      }
    }
    
    class TodoStore {
      @observable todos = []
    
      constructor(rootStore) {
        this.rootStore = rootStore
      }
    }
    
    class RootStore {
      constructor() {
        this.userStore = new UserStore(this)
        this.todoStore = new TodoStore(this)
      }
    }
    
    export default new RootStore()
    
    

    将根store(rootStore)注入到view层根组件之中(App.js),这一点类似与react-redux

    import React from 'react';
    import {Provider, observer} from 'mobx-react';
    import rootStore from './store/store';
    import Demo from './views/Demo';
    
    class App extend React.Component {
        render() {
            return (
                <Provider rootStore={rootStore}>
                    <Demo />
                </Provider>
            )
        } 
    }
    
    export default App;

    Demo组件

    import React from 'react';
    import {inject, observer} from 'mobx-react';
    
    @inject('rootStore')  //注入Provider提供的rootStore到该组件的props中
    @observer //设置当前组件为观察者,一旦检测到store中被监测者发生变化就会进行视图的强制刷新
    class Demo extends React.Component {
        constructor(props) {
            super(props);
            console.log(props); 
        }
        render() {
            let rootStore = this.props.rootStore;
            return (
                <div className="demo">
                    {
                        rootStore.todoStore.map(function(item, index) {
                            return (
                                <div>{item.content}</div>
                            )
                        })
                    }
                </div>
            )
        }
    }
    
    export default Demo;

    整体的rootStore注入机制采用react提供的context来进行传递

    展开全文
  • ReactMobX使用

    2018-09-19 15:23:48
    由于最近开启一个新的个人小项目,准备还是使用 React 及其生态来实现整个技术架构,之前一直使用的是 React + React-Router + Redux 组合,虽然说使用 Redux 来管理整个应用的数据流有着优点,但是 Redux 的写法...

    前言

    由于最近开启一个新的个人小项目,准备还是使用 React 及其生态来实现整个技术架构,之前一直使用的是 React + React-Router + Redux 组合,虽然说使用 Redux 来管理整个应用的数据流有着优点,但是 Redux 的写法繁琐也确实让人诟病,当然这里并不是说 Redux 不好。
    基于项目本身并不大,决定寻找一个新的解决方案,而 MobX 在之前就有所耳闻(只是一直没有时间和需求去深入了解),借着这次机会正好可以好好学习下 MobX 的理念。

    本文中强烈建议使用 ES6&ES7 的语法并且本文也只用 ES6&ES7 语法来举例实现。


    开始使用

    START!!!?

    首先第一步当然是引入 MobX,这里很简单,两种方式:

    1. 使用 npm 安装然后引入:
    npm install mobx;
    
    import { ... } from 'mobx';
    
    1. 使用 script 标签引入:
    <script src="https://unpkg.com/mobx/lib/mobx.umd.js"></script>
    

    在 MobX 的使用中,使用 ES7 语法的 修饰器(Decorator) 将可以极大的简化组织代码,当然,如果使用 ES5 的语法也未尝不可,但是我这里还是强烈建议大家使用 修饰器,并且本文中的所有例子也都基于修饰器来说明。

    对于修饰器这里简要说明一下,修饰器其实是对于一种函数形式的语法糖,通过以下例子可以一目了然其行为作用:

    @decorator
    class A {}
    
    // 等同于
    class A {}
    A = decorator(A) || A;
    

    配置 ES6 以及 修饰器 ,最方便的当然是使用 babel 来编译 ES6 代码了,在 .babelrc 中配置:

    {
      "presets": [
        "es2015",
        "stage-1"
      ],
      "plugins": ["transform-decorators-legacy"]
    }
    

    这里使用了 ES6 中 stage-1 提案标准,然后加入 transform-decorators-legacy 来支持修饰器。


    核心概念

    数据流

    在一个数据管理框架&库中,其最重要的就是它的数据管理模式了,也就是其数据流。
    对于 MobX 来说,它的数据流简明清晰,并且也是单向数据流,如下图所示。

    Mbox 的数据流图片来源:http://cn.mobx.js.org/

    它由几个部分组成:Actions、State、Computed Values、Reactions

    在整个数据流中,通过事件驱动(UI 事件、网络请求…)触发 Actions,在 Actions 中修改了 State 中的值,这里的 State 既应用中的 store 树(存储数据),然后根据新的 State 中的数据计算出所需要的计算属性(computed values)值,最后响应(react)到 UI 视图层。

    当然,如此说明仍然是过于抽象,接下来就进入实际例子分析。

    例子

    const { observable, action, computed, autorun } = mobx;
    
    class Store {
      @observable list = []
      @computed get total() {
        return this.list.length;
      }
      @action change () {
        this.list.push(this.list.length);
      }
    };
    
    const mstore = new Store();
    
    setInterval(() => {
      mstore.change();
    }, 2000);
    
    autorun(() => {
      console.log(mstore.total);
    });
    

    运行这个例子,将可以看到控制台打印出来的数据,我们通过下面几个部分来分析代码。

    可观察状态(State)

    在上面的例子中,定义了一个 Store 类作为数据存储,通过 @observable 修饰器可以将其中的属性转变为可观察的状态值,其语法为:

    @observable  classProperty = value
    

    @observable 接受任何类型的 js 值(原始类型、引用、纯对象、类实例、数组和、maps),observable 的属性值在其变化的时候 mobx 会自动追踪并作出响应。

    当 value 是一个对象类型值的时候,它会默认克隆该对象并且把其中每个属性变为可观察的值,这里默认是深拷贝,也就是说其对象的后代属性都会变成可观察的,比如 @observable classProperty = { obj: { name: 'q' } } ,当 classProperty.obj.name 改变的时候,在 MobX 中也是可以观察到并响应的;

    当然在这里可以加一些调节器来做一些配置:

    • @observable.deep (默认)对对象进行深拷贝;
    • @observable.shallow 它只对对象进行浅拷贝;
    • @observable.ref 禁用对象的自动转化,只转化其引用;

    这里需要注意的是,当定义好其 observable 的对象值后,对象中后来添加的值是不会变为可观察的,这时需要使用 extendObservable 来扩展对象:

    const { observable, action, computed, autorun, extendObservable } = mobx;
    
    class Store {
      @observable oo = {
        name: 1
      }
    };
    
    const mstore = new Store();
    
    extendObservable(mstore, {
      oo: {
        age: 0
      }
    });
    
    var i = 1;
    setInterval(() => {
      mstore.oo.age = i++;
    }, 2000);
    
    autorun(() => {
      console.log(mstore.oo.age);
    });
    

    计算属性值(Computed Values)

    计算属性值实际上是一类衍生值,它是根据现有的状态或者其他值计算而来,原则上在计算属性中尽可能地不对当前状态做任何修改;
    同时对于任何可以通过现有状态数据得到的值都应该通过计算属性获取。
    语法为:@computed get computesValue [function]

    如上面的例子中,只需要获取其 list 属性的总数 total 的时候,我们可以根据其 list 来计算出 total,

    class Store {
      @observable list = []
      @computed get total() {
        return this.list.length;
      }
      @action change () {
        this.list.push(this.list.length);
      }
    };
    
    autorun(() => {
      console.log(mstore.total);
    });
    

    同时,当状态改变使得计算属性的值发生改变的时候,其也是可观察到的。

    在 store 对象中,还可以定义 state 属性的 setter:

    class Store {
      @observable length = 2;
      @computed get squared() {
        return this.length * this.length;
      }
      set squared(value) {
        this.length = Math.sqrt(value);
      }
    }
    

    在每次改变 Store.squared 的时候,会先运行 set squared 函数,从而改变 Store 中的 state。

    动作(Action)

    在 MobX 中,对于 store 对象中可观察的属性值,在他们改变的时候则会触发观察监听的函数,这里注意两点:

    • 该属性必须是定义的可观察属性(@observable)
    • 它的值必须发生改变(和原值是不等的):
    class Store {
      @observable list = []
      @observable name = '2'
      @observable oo = {
        age: 1
      }
    };
    
    const mstore = new Store();
    
    // 触发观察监听的函数
    mstore.list.push('1');
    
    // 或者
    mstore.name = 'h';
    
    // 或者
    mstore.oo.age = 12;
    
    // 这个情况下是不会触发观察,因为 age 属性并不可观察
    mstore.age = 10;
    
    // 这个情况下也不会触发观察,因为其值没有发生变化
    mstore.oo.age = 1;
    

    在 MobX 中,其本身并不会对开发者作出任何限制去如何改变可观察对象;
    但是,它还是提供了一个可选的方案来组织代码与数据流,@action,其规定对于 store 对象中所有可观察状态属性的改变都应该在 @action 中完成,它使代码可以组织的更好,并且对于数据改变的时机也更加清晰。

    语法形式:@action actionFuncName[function]

    const { observable, action, computed, autorun } = mobx;
    
    class Store {
      @observable list = []
      @computed get total() {
        return this.list.length;
      }
      @action change (i) {
        this.list.push(i);
      }
    };
    const mstore = new Store();
    
    var i = 0;
    autorun(() => {
      console.log(mstore.total);
    });
    
    mstore.change(i++);
    

    可以看到,这里将 store 中 list 属性的改变都放在 @action change 函数之中,外加只需要调用该函数即可。

    运行观察(autorun)

    在上面的例子中,当触发了可观察状态属性的改变后,其变化的监听则是在传入 autorun 函数中作出响应。

    autorun 接受一个函数作为参数,在使用 autorun 的时候,该函数会被立即调用一次,之后当该函数中依赖的可观察状态属性(或者计算属性)发生变化的时候,该函数会被调用,注意,该函数的调用取决的函数中使用了哪些可观察状态属性(或者计算属性)。

    例子 1:

    const { observable, action, computed, autorun } = mobx;
    
    class Store {
      @observable count = 0;
      @action add () {
        this.count = this.count + 1;
      }
    };
    
    const mstore = new Store();
    
    setInterval(() => {
     mstore.add();
    }, 2000);
    
    autorun(() => {
      console.log(mstore.count);
    });
    

    在该例子中,autorun 的函数依赖了 mstore.count 属性,该属性是可观察的,其每次变化都会加 1 ,因此其中的函数在第一次立即触发,之后每次改变 mstore.count 的值都会被触发;

    例子 2:

    const { observable, action, computed, autorun } = mobx;
    
    class Store {
      @observable count = 0;
      @computed get result() {
        return this.count + 100;
      }
      @action add () {
        this.count = this.count + 1;
      }
    };
    
    const mstore = new Store();
    
    setInterval(() => {
     mstore.add();
    }, 2000);
    
    autorun(() => {
      console.log(mstore.result);
    });
    

    该例子中和 例子1 是类似的,auto 中的函数依赖了计算属性 mstore.result ,其每次变化的时候也都会触发该函数;

    例子 3:

    const { observable, action, computed, autorun } = mobx;
    
    class Store {
      @observable count = 0;
      @computed get result() {
        return this.count + 100;
      }
      @action add () {
        this.count = this.count;
      }
    };
    
    const mstore = new Store();
    
    setInterval(() => {
     mstore.add();
    }, 2000);
    
    autorun(() => {
      console.log(mstore.result);
    });
    

    在该例子中,只在使用 autorun 的时候触发了一次其传入的函数,之后即使调用 mstore.add() 也并未观察到,这是因为之后的调用中 mstore.result 并没有改变,所以不会触发观察;

    例子 4:

    const { observable, action, computed, autorun } = mobx;
    
    class Store {
      count = 0;
      @action add () {
        this.count = this.count;
      }
    };
    
    const mstore = new Store();
    
    setInterval(() => {
     mstore.add();
    }, 2000);
    
    autorun(() => {
      console.log(mstore.count);
    });
    

    在该例子中也只是在使用 autorun 的时候调用了一次其传入的函数,之后 mstore.count 的值即使改变也并没有触发观察,这是因为 mstore.count 并不是可观察的。

    在实际使用中,autorun 中的函数就是用来操作 Reactions 的,当可观察状态属性的值发生改变的时候,可以在该函数中利用状态值来更新改变 UI 视图(记录日志、持久化),在 MobX 结合 React 的使用中,mobx-react 库则是封装了 autorun 用来在 store 中的可观察状态属性值发生改变的时候 rerender React 组件。


    异步行为

    在很多时候,比如网络请求 ,其 Actions 行为是异步的,这里通过以下一个例子说明如何编写异步的 Action:

    import { observable, action } from "mobx";
    import axios from "axios";
    
    export default class Store {
      @observable authenticated;
      @observable authenticating;
      @observable items;
      @observable item;
    
      @observable testval;
    
      // 初始化 state
      constructor() {
        this.authenticated = false;
        this.authenticating = false;
        this.items = [];
        this.item = {};
    
        this.testval = "Hello";
      }
    
      async fetchData(pathname, id) {
        let { data } = await axios.get(
          `localhost:3000/${pathname}`
        );
        data.length > 0 ? this.setData(data) : this.setSingle(data);
      }
    
      @action setData(data) {
        this.items = data;
      }
    
      @action setSingle(data) {
        this.item = data;
      }
    
      @action clearItems() {
        this.items = [];
        this.item = {};
      }
    
      @action authenticate() {
        return new Promise((resolve, reject) => {
          this.authenticating = true;
          setTimeout(action(() => {
            this.authenticated = !this.authenticated;
            this.authenticating = false;
            resolve(this.authenticated);
          }), 100);
        });
      }
    }
    

    在 React 中使用 MobX

    在 React 中使用 MobX 需要用到 mobx-react。
    其提供了 Provider 组件用来包裹最外层组件节点,并且传入 store(通过)context 传递给后代组件:

    import { Provider } from 'mobx-react';
    const stores = {
      ...
    };
    
    ReactDOM.render((
      <Provider {...stores}>
        <App />
      </Provider>
    ), document.getElementById('root'));
    

    使用 @inject 给组件注入其需要的 store(利用 React context 机制);
    通过 @observer 将 React 组件转化成响应式组件,它用 mobx.autorun 包装了组件的 render 函数以确保任何组件渲染中使用的数据变化时都可以强制刷新组件:

    import React from 'react';
    import { inject, observer } from 'mobx-react';
    
    @inject('userStore', 'commonStore')
    @observer
    export default class App extends React.Component {
    
      componentWillMount() {
        if (this.props.commonStore.token) {
          this.props.userStore.pullUser()
            .finally(() => this.props.commonStore.setAppLoaded());
        } else {
          this.props.commonStore.setAppLoaded();
        }
      }
    
      render() {
        if (this.props.commonStore.appLoaded) {
          return (
            <div>
              ...
              {this.props.children}
            </div>
          );
        }
        return (
          ...
        );
      }
    }
    

    TIP

    useStrict

    在 mobx 中,可以有很多种方式去修改 state,mobx 并不对其做限制;
    但是如果使用了严格模式:

    import { useStrict } from 'mobx';
    
    useStrict(true);
    

    那么将会限制开发者只能通过 @action 来修改 state,这将会更有利于组织代码以及使数据流更清晰。


    总结

    MobX 的理念是通过观察者模式对数据做出追踪处理,在对可观察属性的作出变更或者引用的时候,触发其依赖的监听函数,在 React 中既是在 @observer 中对组件进行数据更新并渲染到视图层面,其核心与开发模式和 Vue 非常相似。

    相比于 Redux 纯函数的形式,它在代码层面却是给开发者减少了不少工作量,但在多人维护的大项目中,个人认为还是 Redux 更加有利,一旦项目中的数据交互增多,其在 MobX 中对于数据流的变化就变得难以理清,而只能依靠约定来限制触发场景。

    在 Redux 于 MobX 的选择中,其两者还是各具优势同时也各有缺点,而如何进行抉择还应该结合项目需求与业务场景。


    参考

    转载请注明来源:https://qiutc.me/post/efficient-mobx.html

    展开全文
  • 官方文档说:MobX 是一个经过战火洗礼的库,它通过透明的函数响应式编程(transparently applying functional reactive programming - TFRP)使得状态管理变得简单和可扩展。MobX背后的哲学很简单: 任何源自应用状态的...
    mobx与react/ReactNative 的用法自学整理
    官方文档说:MobX 是一个经过战火洗礼的库,它通过透明的函数响应式编程(transparently applying functional reactive programming - TFRP)使得状态管理变得简单和可扩展。MobX背后的哲学很简单:
    任何源自应用状态的东西都应该自动地获得。其中包括UI、数据序列化、服务器通讯,等等。
    React 和 MobX 是一对强力组合。React 通过提供机制把应用状态转换为可渲染组件树并对其进行渲染。而MobX提供机制来存储和更新应用状态供 React 使用。
    对于应用开发中的常见问题,React 和 MobX都提供了最优和独特的解决方案。React 提供了优化UI渲染的机制, 这种机制就是通过使用虚拟DOM来减少昂贵的DOM变化的数量。
    MobX 提供了优化应用状态与 React 组件同步的机制,这种机制就是使用响应式虚拟依赖状态图表,它只有在真正需要的时候才更新并且

    其实mobx的模式是类MVVM 怎么说呢 就是用法是是双向数据绑定的用法但是底层还是单向数据流(个人认为)
    安装:
    npm install mobx mobx-react --save
    安装babel插件 用于支持ES7的decorator(装饰)特性
    npm install babel-plugin-transform-decorators-legacy babel-react-native-stage-0 --save-dev
    现在,创建一个 .babelrc 文件配置 babel 插件:
    { 'presets': ['react-native'], 'plugins': ['transform-decorators-legacy']}

    引入:
    import {observable,autorun} from 'mobx'
    import {observer} from 'mobx-react/react'
    因为我们编写的是一个自定义 .babelrc 文件,所有只需要 react-native 的 preset。配置 react-native 的 preset,还有指定一些先期运行的插件(我们这里是 transform-decorators-legacy 插件)。

    首先说一下mobx载react-native中的思路
    主要用到的是@observable、@observer、@computed、@action(几乎很少用)
    他们之间的关系和用法:
    我刚开始的时候也是一头雾水 因为我不知道什么是Radus、也不知道MOBX但是由于项目需要(我工作一年几乎都没有算入门....这是悲哀啊)
    这里用es6
    当你创建一个class组件时在前面加上@observer (观察者)
    在组件中定义一个使用@observable 去监听一个数值(这个数据可以数字、字符串、数组、对象等类型)
    当你监听的数值发生变化时 就会触发@observer所观察的组件的render方法实现页面重新渲染 实现数据更新
    @computed是可以根据你的需求动态的去计算 什么时候需要更新什么时候不需要更新
    @action 是当你监听的多个数据发生变化时可以统一放在action({})中去处理 当action中的数据全部变化完以后再调用render方法 一次更新 (这里是相当于一个优化)

    https://www.jianshu.com/p/505d9d9fe36a(这里写的非常详细,大赞)
    选取部分代码如下:
    class MyState {
    @observable num1 = 0;
    @observable num2 = 100;
    @action addNum1 = () => { this.num1 ++; };
    @action addNum2 = () => { this.num2 ++; };
    @computed get total() { return this.num1 + this.num2; }
    const newState = new MyState();
    const AllNum = observer((props) => <div>num1 + num2 = {props.store.total}</div>);
    const Main = observer((props) => (
    <div>
    <p>num1 = {props.store.num1}</p>
    <p>num2 = {props.store.num2}</p>
    <div>
    <button onClick={props.store.addNum1}>num1 + 1</button>
    <button onClick={props.store.addNum2}>num2 + 1</button>
    </div>
    </div>));
    @observerexport default class App extends React.Component {
    render() {
    return (
    <div>
    <Main store={newState} />
    <AllNum store={newState} />
    </div>
    );
    }}
    展开全文
  • react-Mobx基本使用

    2019-07-08 17:48:57
    十分钟交互MobX + React 教程 mobx 的核心理念是 简单、可扩展的状态管理库。比redux和react-redux方便许多 先create-react-app 构建一个项目 1.装包 1.1安装mobx mobx-react npm install mobx mobx-react -S ...
  • Mobx提供了一个mobx-react包帮助开发者方便地在React中使用Mobxmobx-react中有observer、Provider、inject几个常用的api。在《mobx系列(二)-mobx主要概念》中我们已经介绍过observer,本文介绍下inject、Provider...
  • 前言 MobX 是 Redux 之后的一个状态管理库,它相较于 redux 更轻量,整体是一个观察者模式的架构,存储 state ...MobX 通过函数响应式编程的思想使得状态管理变得简单和易于扩展,其背后的哲学是:任何从应用程序的...
  • Using HOC via es7 Decorators SyntaxError: Support for the experimental syntax ‘decorators-legacy’ isn’t ...MobX结合ReactNative使用; MobX使用中重要的关键字:observer observable action when autorun..
  • React-Mobx 基础学习

    2020-03-08 23:51:55
    Mobx 和 Redux 一样都是状态管理库,需要注意的是他们都是属于 js,即你可以在 React中使用,也可以在 Angular、Vue中使用,本身并不会有限制。 正如大多数对比 Mobx 和 Redux 的文章–这里不对比孰好孰坏(实际上我...
  • React进阶之路系列学习笔记:React进阶之路系列学习笔记 github源码:React_learning 11.0 MoBX知识结构与核心概念 1.MobX知识结构 2.MobX数据流管理状态   3.MobX核心API 1、obse...
  • Github 仓库: https://github.com/SangKa/mobx-docs-cn入门MobX 是一个经过战火洗礼的库,它通过透明的函数响应式编程(transparently applying functional reactive programming - TFRP)使得状态管理变得简单和可...
  • React 状态管理库: Mobx

    2017-08-13 13:56:34
    React 维护了状态到视图的映射关系,开发者只需关心状态即可,由 React 来操控视图。 在小型应用中,单独使用 React 是没什么问题的。但在复杂应用中,容易碰到一些状态管理方面的问题,如: React 只提供了...
  • Todo-list 这是一个用来初步了解如何通过 React + ...技术栈: React + Mobx + React-Mobx + SCSS。由于刚接触 React 不久,写的不好或者有误还请指出,万分感谢。 React React 是一个用于构建用户界面的 JavaScri...
  • react mobx入门初体验

    2018-11-14 09:27:11
    理解响应式编程的概念 正确使用mobx关键api达到维护应用程序状态的目标 2.什么是修饰器? Decorator是在 声明阶段 实现类与类成员注解的一种语法。 说的直白点Decorator就是 添加 或者 修改 类的变量与方法。 ...
  • MobX 是一个简单的、可扩展的状态管理器,他通过透明的函数式编程使得状态管理变的简单和可扩展 ReactMobX 是一对强力组合。React 通过提供机制把应用状态转换为可渲染组件树并对其进行渲染。而 MobX 提供...
  • react中使用typescript创建项目 create-react-app react-ts --scripts-version=react-scripts-ts 输入y,不要点回车,成功后的项目目录如下: node_modules直接装好了,cd react-ts npm run start项目跑起来。...
  • MobX 是一个简单、可伸缩的响应式状态管理库。通过 MobX 你可以用最直观的方式修改状态,其他的一切 MobX 都会为你处理好(如自动更新UI),并且具有非常高的性能。当状态改变时,所有应用到状态的地方都会自动更新...
1 2 3 4 5 ... 20
收藏数 750
精华内容 300
关键字:

mobx函数响应式 react