状态管理库 MobX 和 react

2021-02-02 09:59:54 浏览数 (1)

MobX

  • MobX 是一个简单、方便扩展、久经考验的状态管理解决方案

基本概念

  • MobX 是一个独立的组件,可以配合各种框架使用,由于项目中需要使用 react & MobX。下面来详细了解一下
  • State 是每一个应用程序的核心部分,而使用一个不合规范的 State 则是让你的应用充满 bug 和失控的不二法门,或者就是局部变量环绕,让你的 state 失去了同步。有很多框架试图解决这个问题,比如使用不可变的 state,但是这样以来又带来了新的问题,比如数据必须规格化,完整性约束失效等等。

MobX 功能

  • MobX 让整个事情又变简单了:它不允许产生失控的 state。它的理念也很简单:所有可以从 state 中派生的事物,都会自动的派生。
  • demo
代码语言:javascript复制
class TodoStore {
	todos = [];

	get completedTodosCount() {
    	return this.todos.filter(
			todo => todo.completed === true
		).length;
    }

	report() {
		if (this.todos.length === 0)
			return "";
		return `Next todo: "${this.todos[0].task}". `   
			`Progress: ${this.completedTodosCount}/${this.todos.length}`; 
	}

    addTodo(task) {
		this.todos.push({ 
			task: task,
			completed: false,
            assignee: null
		});
	}
}

const todoStore = new TodoStore();
复制代码

当我们去创建一个 todoStore,他拥有一个 todos 集合,现在我们往这个 todoStore 里添加一些东西,为了明显起见,就调用 todoStore.report

代码语言:javascript复制

todoStore.addTodo("read MobX tutorial");
console.log(todoStore.report());
​
todoStore.addTodo("try MobX");
console.log(todoStore.report());
​
todoStore.todos[0].completed = true;
console.log(todoStore.report());
​
todoStore.todos[1].task = "try MobX in own project";
console.log(todoStore.report());
​
todoStore.todos[0].task = "grok MobX tutorial";
console.log(todoStore.report());

  • 太巧了,这就是 MobX 能为你做的事情。自动执行只在 state 改变的时候触发,就好像 Excel 中的图表只在单元格数据改变时更新一样。为了达到这个目标,TodoStore 必须成为可观测的(observable)才行,让我们来改一些代码。
observable & computed

同时,completedTodosCount 属性应该被自动派生,使用 @observable 和 @computed 装饰器来做这些事情:

代码语言:javascript复制
class ObservableTodoStore {
    @observable todos = [];
    @observable pendingRequests = 0;
 
    constructor() {
        mobx.autorun(() => console.log(this.report));
    }
 
    @computed get completedTodosCount() {
    	return this.todos.filter(
			todo => todo.completed === true
		).length;
    }
 
    @computed get report() {
        if (this.todos.length === 0)
            return "";
	return `Next todo: "${this.todos[0].task}". `   
	    `Progress: ${this.completedTodosCount}/${this.todos.length}`; 
	}
 
    addTodo(task) {
	this.todos.push({ 
	    task: task,
	    completed: false,
	    assignee: null
	});
    }
}
 
const observableTodoStore = new ObservableTodoStore();

复制代码
  • 在这个构造器中,我们使用 autorun 包裹了一个打出 report 的小函数。Autorun 里的东西首先会运行一次,然后当其中的函数有 observable 的数据发生变化时,会再次运行。 这里我们使用了 todos 属性,每次 todos 变化了我们就打印出新的东西。
  • 测试一下
代码语言:javascript复制

observableTodoStore.addTodo("read MobX tutorial");
observableTodoStore.addTodo("try MobX");
observableTodoStore.todos[0].completed = true;
observableTodoStore.todos[1].task = "try MobX in own project";
observableTodoStore.todos[0].task = "grok MobX tutorial";

举个栗子(sf 的一个问题有感)

  • 对于单个对象,我可以使用computed通过计算获得一些属性,比如
代码语言:javascript复制
@observable good = {
    number: 2,
    price: 3
}
@computed get totalPrice() {
    return this.good.number * this.good.price;
}

// 数组
@observable goodsList = [{
    number: 2,
    price: 3
},{
    number: 2,
    price: 3
}]
  • 问题?
    • 这种情况我如何通过computed获得数组某个元素的计算属性呢,还是只能在改变number的函数中手动去更改,但是我数组的对象中并没有一个totalPrice的属性,每次把单个good push到goodsList中去还要给good添加一个totalPrice属性岂不是很麻烦
  • 解决方案
    • good 弄成一个单独的model文件
代码语言:javascript复制
export default class Good{
  @observable number;
  @observable price;
  constructor(number, price) {
    this.number = number;
    this.price = price;
  }
  
  @computed
  get totalPrice() {
    return this.number * this.price
  }   

}
复制代码
    • 然后在goodList文件中
    • 这样就实现了自动计算, 访问的时候类似 this.props.goodList[0].totalPrice
代码语言:javascript复制
  @action
  addGood(...args) {
    this.todos.push(new Good(...args));
  }
  • 未完待续...

总结

  • 最后总结一些:
  • @observale 修饰器或者 observable 函数让对象可以被追踪;
  • @computed 修饰器创造了自动运算的表达式;
  • autorun 函数让依靠 observable 的函数自动执行,这个用来写 log,发请求很不错;
  • @observer 修饰器让 React 组建自动起来,它会自动更新,即便是在一个很大的程序里也会工作的很好;
  • MobX 不是一个状态容器

很多人把 MobX 当作另外一个 Redux,但是它仅仅是一个库,不是一个什么架构。上面的例子还是需要程序员自己去组织逻辑和 store 或者控制器什么的.

引用:

10分钟极速入门 MobX

sf @computed使用

react 官网

0 人点赞