美文网首页
Mobx 入门和进阶

Mobx 入门和进阶

作者: 一本正经的反派 | 来源:发表于2019-04-16 19:57 被阅读0次

Mobx 数据管理模式,通过行为修改状态,然后更新到视图。

  1. Mobx 的写法
    mobx 采用了ES7 语法的修饰器
function setAge(target){
    target.age = 28;
}
@setAge
class Person {}
// 等同于
Person = setAge(Person) || Person;
console.log(Person.age);

利用装饰器代理函数使用起来更方便。 B格更高

  1. 常用的三个属性

observable 观察者
action 行为动作(唯一可以改变state)
computed 计算属性


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

核心部分

  1. 可观察状态(State)
    @observable 修饰器将其中的属性转变为可观察的状态值
@observable  classProperty = value

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

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

@observable classProperty = { obj: { name: 'q' } } 

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

  1. 追加属性的观察
    这时需要使用 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);
});
  1. 计算属性值(Computed Values)

是一类衍生值,它是根据现有的状态或者其他值计算而来。
两个原则:

1、计算属性中尽可能地不对当前状态做任何修改;
2、任何可以通过现有状态数据得到的值都应该通过计算属性获取。

@computed get computesValue [function];
  1. 动作(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;

存在异步行为,比如网络请求

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);
    });
  }
}
  1. 运行观察(autorun)

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

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

React 中使用 MobX​​​​​​​

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

核心

核心
@Provider

Provider 组件用来包裹最外层组件节点,并且传入 store(通过)context 传递给后代组件:

import { Provider } from 'mobx-react';
const stores = {
  ...
};

ReactDOM.render((
  <Provider {...stores}>
    <App />
  </Provider>
), document.getElementById('root'));

@inject
@observer

@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:

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

import { useStrict } from 'mobx';

useStrict(true);

总结

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

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

相关文章

网友评论

      本文标题:Mobx 入门和进阶

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