您现在的位置是:首页 >技术杂谈 >简要记录一下MobX的使用及内置装饰器的作用网站首页技术杂谈
简要记录一下MobX的使用及内置装饰器的作用
MobX 是一个简单、可扩展的状态管理库,它可以帮助管理 React 应用程序中的状态。要使用 MobX,需要进行以下步骤:
使用步骤
-
安装 MobX 和 mobx-react:
npm install mobx mobx-react --save
-
创建一个 store:
import { observable, action } from 'mobx'; class Store { @observable count = 0; @action increment() { this.count++; } @action decrement() { this.count--; } } export default new Store();
-
在组件中使用 store:
import React from 'react'; import { observer } from 'mobx-react'; import store from './store'; const Counter = observer(() => ( <div> <h1>{store.count}</h1> <button onClick={() => store.increment()}>+</button> <button onClick={() => store.decrement()}>-</button> </div> )); export default Counter;
内置修饰器
@observable、@observer、observe
@observable 是 MobX 库中的一个装饰器,用于将一个普通的 JavaScript 对象属性转换为可观察的状态。当使用 @observable 装饰器修饰一个属性时,MobX 会自动为该属性创建一个可观察对象,并在属性值发生变化时自动更新相关的数据流。
以下是一个使用 @observable 装饰器的示例:
import { observable } from 'mobx';
class MyStore {
@observable count = 0;
@observable name = 'John';
}
在这个示例中,我们定义了一个名为 MyStore 的类,并使用 @observable 装饰器将 count 和 name 属性转换为可观察状态。这意味着当 count 或 name 属性的值发生变化时,MobX 会自动更新相关的数据流,以反映新的状态。
我们可以在组件中使用 MyStore 类的实例,并通过访问 count 和 name 属性来读取和更新状态。例如:
import { observer } from 'mobx-react';
import { MyStore } from './MyStore';
@observer
class MyComponent extends React.Component {
render() {
return (
<div>
<p>Count: {MyStore.count}</p>
<p>Name: {MyStore.name}</p>
<button onClick={() => MyStore.count++}>Increment</button>
<button onClick={() => MyStore.name = 'Jane'}>Change name</button>
</div>
);
}
}
在这个示例中,我们使用 @observer 装饰器将 MyComponent 类转换为可观察组件,并通过访问 MyStore.count 和 MyStore.name 属性来读取和更新状态。当用户单击 “Increment” 按钮时,count 属性的值会增加 1;当用户单击 “Change name” 按钮时,name 属性的值会更改为 “Jane”。由于 MyComponent 类已被转换为可观察组件,因此当 count 或 name 属性的值发生变化时,React 会自动重新渲染组件,以反映新的状态。
在 MobX 中,observe 是一个函数,它可以用于观察可观察对象的变化并在变化时执行回调函数。observe 的语法如下:
observe(target: Object, callback: (change: Object) => void, fireImmediately?: boolean): Lambda
参数说明:
target:要观察的可观察对象。
callback:当可观察对象发生变化时要执行的回调函数。
fireImmediately:一个可选的布尔值,表示是否在观察开始时立即执行回调函数,默认为 false。
observe 返回一个函数,调用该函数可以取消观察。
import { observable, observe } from 'mobx';
const person = observable({
name: 'Alice',
age: 30,
});
const disposer = observe(person, (change) => {
console.log(change);
});
person.age = 31; // 输出 { type: 'update', object: { name: 'Alice', age: 31 }, oldValue: 30, name: 'age' }
disposer(); // 取消观察
这个示例中,我们观察了一个名为 person 的可观察对象,并在它发生变化时打印出了变化的信息。当我们修改 person 的 age 属性时,observe 的回调函数将被执行,并输出了变化的信息。最后,我们通过调用返回的 disposer 函数取消了观察。
extendObservable
extendObservable
是 MobX 中的一个函数,它可以用于将属性添加到已有的对象上并使它们成为可观察的。语法如下:
extendObservable(target: Object, properties: Object, decorators?: Object): Object
参数说明:
target
:要添加属性的对象。properties
:一个对象,其中包含要添加到target
的属性及其初始值。decorators
:一个可选的对象,其中包含要应用于属性的修饰符函数。
extendObservable
返回一个与 target
相同的对象,但已经添加了可观察的属性。
下面是一个示例:
import { extendObservable } from 'mobx';
const person = {
name: 'Alice',
};
extendObservable(person, {
age: 30,
});
console.log(person.age); // 输出 30
在这个示例中,我们使用 extendObservable
将 age
属性添加到 person
对象上,并将其初始值设置为 30
。现在,我们可以像访问普通属性一样访问 person.age
属性,并且它也是可观察的。
如果想要应用修饰符函数,可以将它们作为第三个参数传递给 extendObservable
。例如:
import { extendObservable, observable } from 'mobx';
const person = {
name: 'Alice',
};
extendObservable(person, {
age: 30,
get fullName() {
return `${this.name} (${this.age})`;
},
}, {
fullName: observable,
});
console.log(person.fullName); // 输出 "Alice (30)"
在这个示例中,我们将 fullName
属性添加到 person
对象上,并应用了 observable
修饰符函数。现在,fullName
属性也是可观察的。
@action、@action.bound
@action
和@action.bound
都是 MobX 中用于声明动作(action)的装饰器。
@action
装饰器可以用于将普通函数转换为动作函数,使其能够修改可观察对象的属性,并在修改后自动通知相关的观察者。使用 @action
装饰器可以让代码更加清晰易懂,因为它明确地表明了哪些函数是动作函数。例如:
import { observable, action } from 'mobx';
class Counter {
@observable count = 0;
@action increment() {
this.count++;
}
@action decrement() {
this.count--;
}
}
在这个示例中,我们使用 @observable
装饰器将 count
属性声明为可观察的,并使用 @action
装饰器将 increment
和 decrement
函数声明为动作函数。现在,当我们调用这些函数时,它们会修改 count
属性并自动通知相关的观察者。
@action.bound
装饰器与 @action
装饰器类似,但它还会自动绑定函数中的 this
。这意味着可以将绑定函数作为回调传递给其他组件或库,并且无需担心 this
的上下文。例如:
import { observable, action } from 'mobx';
class Counter {
@observable count = 0;
@action.bound
increment() {
this.count++;
}
@action.bound
decrement() {
this.count--;
}
}
在这个示例中,我们使用 @action.bound
装饰器将 increment
和 decrement
函数声明为动作函数,并自动绑定了函数中的 this
。现在,我们可以将这些函数作为回调传递给其他组件或库,并且无需担心 this
的上下文。
@computed
@computed
是 MobX 中用于声明计算属性(computed property)的装饰器。
计算属性是一种特殊的可观察对象,它的值是从其他可观察对象中派生出来的。当它所依赖的可观察对象发生变化时,计算属性的值会自动重新计算。使用 @computed
装饰器可以将一个普通的 getter 方法转换为计算属性。例如:
import { observable, computed } from 'mobx';
class Order {
@observable price = 10;
@observable quantity = 2;
@computed get total() {
return this.price * this.quantity;
}
}
在这个示例中,我们使用 @observable
装饰器将 price
和 quantity
属性声明为可观察的,并使用 @computed
装饰器将 total
方法声明为计算属性。现在,当我们访问 order.total
属性时,它会自动计算并返回 price * quantity
的值。如果 price
或 quantity
属性发生变化,total
属性的值也会自动更新。
另外还可以使用 set
方法来实现带有 setter 的计算属性。例如:
import { observable, computed } from 'mobx';
class Temperature {
@observable celsius = 25;
@computed get fahrenheit() {
return this.celsius * 1.8 + 32;
}
set fahrenheit(value) {
this.celsius = (value - 32) / 1.8;
}
}
在这个示例中,我们使用 @observable
装饰器将 celsius
属性声明为可观察的,并使用 @computed
装饰器将 fahrenheit
方法声明为计算属性。我们还实现了一个带有 setter 的 fahrenheit
计算属性,它会根据当前的 celsius
值自动计算出相应的 fahrenheit
值,并将其设置为 celsius
属性的值。现在,我们可以通过访问 temperature.fahrenheit
属性来获取或设置温度值,而无需手动进行转换。
Provider、@inject()
@inject('')
装饰器通常与 Provider
组件一起使用,用于将 store 注入到组件中。
在 MobX 中,Provider
组件用于提供一个 store 实例,并将该实例传递给需要访问该 store 的组件。Provider
组件接受两个属性:store
和 storeName
。其中,store
属性指定要提供的 store 实例,storeName
属性指定 store 的名称(可选)。例如:
import { Provider } from 'mobx-react';
import myStore from './myStore';
ReactDOM.render(
<Provider store={myStore}>
<App />
</Provider>,
document.getElementById('root')
);
在这个示例中,我们使用 Provider
组件提供了一个名为 myStore
的 store 实例,并将其传递给 App
组件。在 App
组件中,我们可以使用 @inject('storeName')
装饰器将 myStore
注入到组件中,并在组件中访问该 store 实例的方法和属性。例如:
import { inject } from 'mobx-react';
@inject('myStore')
class MyComponent extends React.Component {
render() {
const { myStore } = this.props;
return (
<div>
<p>Count: {myStore.count}</p>
<button onClick={() => myStore.increment()}>+</button>
<button onClick={() => myStore.decrement()}>-</button>
</div>
);
}
}
在这个示例中,我们使用 @inject('myStore')
装饰器将 myStore
注入到 MyComponent
组件中,然后在组件中通过 this.props.myStore
访问该 store 实例的方法和属性。
需要注意的是,Provider
组件必须在组件树的最顶层,以便所有子组件都能访问到 store 实例。另外,storeName
属性是可选的,如果没有指定,则默认使用 store 实例的名称作为名称。
7. toJS
toJS
是 MobX 中的一个函数,用于将一个可观察对象转换为普通的 JavaScript 对象。具体来说,toJS
函数会递归遍历一个可观察对象及其所有子属性,将它们转换为普通的 JavaScript 对象或数组,以便在不需要响应式特性时使用。
在 MobX 中,所有的可观察对象都是响应式的,即当它们的值发生变化时,会自动触发相关的响应。但是,在某些情况下,我们可能需要将一个可观察对象转换为普通的 JavaScript 对象,以便进行序列化、传输或存储等操作。这时,就可以使用 toJS
函数来实现。
以下是一个示例代码:
import { observable, toJS } from 'mobx';
const person = observable({
name: 'Alice',
age: 20,
address: {
city: 'Shanghai',
country: 'China',
},
});
const plainObject = toJS(person);
console.log(plainObject);
// 输出:{ name: 'Alice', age: 20, address: { city: 'Shanghai', country: 'China' } }
在这个示例代码中,我们首先定义了一个可观察对象 person
,它包含一个普通属性 name
和一个嵌套的可观察对象 address
。然后,我们使用 toJS
函数将 person
转换为普通的 JavaScript 对象,并将其赋值给变量 plainObject
。最后,我们将 plainObject
输出到控制台中。
需要注意的是,使用 toJS
函数将可观察对象转换为普通的 JavaScript 对象后,它就不再具有响应式特性了。如果需要重新将一个普通的 JavaScript 对象转换为可观察对象,则可以使用 MobX 中的 observable
函数来实现。
除以上几个常用的函数之外还有一些其它的,比如:autorun(fn):创建一个自动运行函数,它会自动跟踪其所依赖的可观察对象,并在其中任何一个发生变化时自动运行。例如:autorun(() => console.log(person.name));
、reaction(expression, effect):创建一个反应函数,它会自动跟踪 expression 所依赖的可观察对象,并在其中任何一个发生变化时运行 effect 函数。例如:reaction(() => person.age, age => console.log('Age changed to', age));
、runInAction(fn):将一个函数包装在一个事务中,并在其中执行所有的可观察对象更改。例如:runInAction(() => { person.name = 'Jane'; person.age = 25; });
等等