您现在的位置是:首页 >技术杂谈 >简要记录一下MobX的使用及内置装饰器的作用网站首页技术杂谈

简要记录一下MobX的使用及内置装饰器的作用

聂大哥 2024-06-17 10:47:03
简介简要记录一下MobX的使用及内置装饰器的作用

MobX 是一个简单、可扩展的状态管理库,它可以帮助管理 React 应用程序中的状态。要使用 MobX,需要进行以下步骤:

使用步骤

  1. 安装 MobX 和 mobx-react:

    npm install mobx mobx-react --save
    
  2. 创建一个 store:

    import { observable, action } from 'mobx';
    
    class Store {
      @observable count = 0;
    
      @action increment() {
        this.count++;
      }
    
      @action decrement() {
        this.count--;
      }
    }
    
    export default new Store();
    
  3. 在组件中使用 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;
    

内置修饰器

  1. @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 函数取消了观察。

  1. 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

在这个示例中,我们使用 extendObservableage 属性添加到 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 属性也是可观察的。

  1. @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 装饰器将 incrementdecrement 函数声明为动作函数。现在,当我们调用这些函数时,它们会修改 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 装饰器将 incrementdecrement 函数声明为动作函数,并自动绑定了函数中的 this。现在,我们可以将这些函数作为回调传递给其他组件或库,并且无需担心 this 的上下文。

  1. @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 装饰器将 pricequantity 属性声明为可观察的,并使用 @computed 装饰器将 total 方法声明为计算属性。现在,当我们访问 order.total 属性时,它会自动计算并返回 price * quantity 的值。如果 pricequantity 属性发生变化,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 属性来获取或设置温度值,而无需手动进行转换。

  1. Provider、@inject()

@inject('') 装饰器通常与 Provider 组件一起使用,用于将 store 注入到组件中。

在 MobX 中,Provider 组件用于提供一个 store 实例,并将该实例传递给需要访问该 store 的组件。Provider 组件接受两个属性:storestoreName。其中,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; });等等

风语者!平时喜欢研究各种技术,目前在从事后端开发工作,热爱生活、热爱工作。