美文网首页
MobX的简单了解

MobX的简单了解

作者: any_5637 | 来源:发表于2019-10-31 20:22 被阅读0次

    MobX

    MobX 是一种简单、可扩展的状态管理,猪齿鱼框架就是用它进行状态管理。

    简单理解

    mobx修饰组件就是把这个全局的跟组件内的state做关联,全局的变了,局部的也变了,进而触发局部的render。

    安装

    • 安装: npm install mobx --save;
    • React 绑定库: npm install mobx-react --save;
    • mobx相关依赖:npm i babel-plugin-transform-class-properties -D用来编译类(class)
      npm i babel-plugin-transform-decorators-legacy -D 用来编译装饰器
      npm install --save-dev @babel/plugin-proposal-decorators 装饰器

    webpack.config.js 添加如下配置

      rules: [{
        test: /\.js$/,
        exclude: /node_modules/,
        use: {
          loader: 'babel-loader',
          options: {
            presets: ['@babel/preset-env','react'],
            plugins: ['transform-decorators-legacy', 'transform-class-properties']
          }
        }
      }]
    

    在react-app项目下支持装饰器的解决方法

    在根目录下面新建.babelr文件,写入:

      {
        "presets": ["@babel/preset-env"],
        "plugins": [
          ["@babel/plugin-proposal-decorators", { "legacy": true }],
          ["@babel/plugin-proposal-class-properties", { "loose": true }]
        ]
      }
    

    常用api

    1. observable 使用:设置可观察数据:使用mobx的observable方法使定义的状态值可以被观察,
      observable 是一种让数据的变化可以被观察的方法,值可以是 JS原始数据类型、引用类型、普通对象、类实例、数组和映射。
      import { observable, autorun } from 'mobx';
      // JS原始类型(Number/String/Boolean)
      const value = observable(0);
      const number = observable(100);
      autorun(() => {
        console.log(value.get());
      }); // 当观测到的数据发生变化的时候,如果变化的值处在autorun中,那么autorun就会自动执行。
      value.set(1);
      value.set(2);
      number.set(101);  // 依次打印 0 1 2
    
      // 数组、对象类型
      const list = observable([1, 2, 4]);
      list.push(5) 
      console.log(list[0], list[1], list[2], list[3]) // 1 2 4 5
    
      const obj = observable({a: '11', b: '22'})
      obj.a = "leo";
      console.log(obj.a, obj.b) // leo 22
    
      // 映射(Map)类型
      const map = observable.map({ key: "value"});
      map.set("key", "new value");
      console.log(map.has('key'))  // true
    

    @observable 使用: 使用装饰器 @observable 来将其转换成可观察的。

      @observer export default class PictureShow extends React.Component {}
    
    1. 响应可观察数据的变化:
    • (@)computed:监听相关状态变化时自动更新的值。
      const number = observable(10);
      const plus = computed(() => number.get() > 0);
    
      autorun(() => {
        console.log(plus.get());
      });
    
      number.set(-19); // number的值变化,触发computed,输出false
      number.set(-1); // number的值变化,因为-1<0,没有改变plus的值,没有输出
      number.set(1); // number的值变化,因为1>0, 输出true
    
    • autorun:修改autorun中任意一个可观察数据即可触发自动运行
        import { observable, autorun } from 'mobx'
        class Store {
            @observable str = 'leo';
            @observable num = 123;
        }
    
        let store = new Store()
        autorun(() => {
            console.log(`${store.str}--${store.num}`)
        })
        // leo--123
    

    computed 与 autorun 区别:
    @computed:用于响应式的产生一个可以被其他 observer 使用的值。
    autorun:不产生新的值,而是达到一个效果(如:打印日志,发起网络请求等命令式的副作用),autorun 默认会执行一次,以获取哪些可观察数据被引用。autorun 的作用是在可观察数据被修改之后,自动去执行依赖可观察数据的行为。
    @computed:如果一个计算值不再被观察了,MobX 可以自动地将其垃圾回收,而 autorun 中的值必须要手动清理才行。

    1. 修改可观察数据
    • action: 修改状态的行为,使用 action 的好处是能将多次修改可观察状态合并成一次,从而减少触发 autorun 或者 reaction 的次数。
      import { observable, computed, reaction, action} from 'mobx';
    
      class Store {
        @observable string = 'leo';
        @observable number = 123;
        @action bar(){
          this.string = 'pingan'
          this.number = 100
        }
      }
      let store = new Store()
      reaction(() => [store.string, store.number], arr => {
        console.log(arr)
      })
      store.bar() // ["pingan", 100]
    
    • runInAction(name?, thunk):action只能影响正在运行的函数,而无法影响当前函数调用的异步操作。
      在回调中需要使用action进行包裹,这里借用官网给出的例子:
      @action createRandomContact() {
      this.pendingRequestCount++;
      superagent
        .get('https://randomuser.me/api/')
        .set('Accept', 'application/json')
        .end(action("createRandomContact-callback", (error, results) => {
          if (error)
            console.error(error);
          else {
            const data = JSON.parse(results.text).results[0];
            const contact = new Contact(this, data.dob, data.name, data.login.username, data.picture);
            contact.addTag('random-user');
            this.contacts.push(contact);
            this.pendingRequestCount--;
          }
      }));
    }
    

    在end中触发的回调函数,被action给包裹了,action无法影响当前函数调用的异步操作,而回调函数是一个异步操作,所以必须再用一个action来包裹住它,这样程序才不会报错。
    如果使用async function来处理,可以使用runInAction这个API来解决之前的问题。

      import {observable, action, useStrict, runInAction} from 'mobx';
      useStrict(true);
    
      class Store {
        @observable name = '';
        @action load = async () => {
          const data = await getData();
          runInAction(() => {
            this.name = data.name;
          });
        }
      }
    

    调用load之后,runInAction可以立刻被执行。

    结合react使用

      import React from 'react';
      import { observable, useStrict, action } from 'mobx';
      import { observer } from 'mobx-react';
      useStrict(true);
    
      class MyState {
        @observable num = 0;
        @action addNum = () => {
          this.num++;
        };
      }
    
      const newState = new MyState();
    
      @observer
      export default class App extends React.Component {
    
        render() {
          return (
            <div>
              <p>{newState.num}</p>
              <button onClick={newState.addNum}>+1</button>
            </div>
          )
        }
      }
    

    这里定义了一个类MyState,包括可以被观察的num变量和action函数来改变num,实例化这个类并在组件中使用,使用@observer修饰App组件,组件中可以改变和观察num的值。

    跨组件交互

    在不使用状态管理的React要实现跨组件交互,通常需要我们在父组件定义state和修改state的函数,然后再通过props传给不同的组件,这样看起来逻辑简单,但在业务很复杂的情况下就会很繁琐,而Mobx可以更加简单的解决问题。

      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>
      ));
    
      @observer
      export default class App extends React.Component {
    
        render() {
          return (
            <div>
              <Main store={newState} />
              <AllNum  store={newState} />
            </div>
          );
        }
      }
    
    

    上面的一段代码很好的解释了跨组件交互:Main和AllNum是两个不相关的组件,在MyState中存放组件共同需要的状态和函数,通过props将状态和函数传给两个子组件,子组件可以调用方法改变相应的状态的值。

    相关文章

      网友评论

          本文标题:MobX的简单了解

          本文链接:https://www.haomeiwen.com/subject/vgizvctx.html