mobx-react快速入门使用

发布时间:2023年12月24日

目录

眼熟一下

Provider

@inject

?@observable

@observer

@action

@computed

完整代码示例?

状态改变和渲染次数的疑惑

最后


注意:本文更多讲的是怎么使用mobx,关于原理等部分只会稍微带过,请查阅MobX中文官网等其他文章。本文使用TypeScript作为示例代码。另外!如果有什么地方说错了,欢迎指正!毕竟俺也是新人~

眼熟一下

首先眼熟一下几个名称:

// mobx最上层声明状态的组件
<Provider></Provider>


// 下面为几个常见的装饰器(decorators),用于定义和管理应用状态和行为
@inject('属性名')

@observable

@observer

@action

@computed

Provider

在 MobX 和 mobx-react 中,Provider 是一个用于将 MobX store 提供给组件树的 React 组件。它是 mobx-react 库提供的一个组件,用于使整个组件树能够访问到应用程序的 MobX 状态。?

import React from 'react';
import { render } from 'react-dom';
import { Provider } from 'mobx-react';
import MyStore from './stores/MyStore'; // 导入你的 MobX store

const myStoreInstance = new MyStore();

const App = () => (
  // 把 myStore 提供给整个后续的组件树,
  // 所有 Provider 的子组件都可以通过 @inject 的注解获取 myStore 
  <Provider myStore={myStoreInstance}>
    {/* 其他组件嵌套在这里 */}
  </Provider>
);

render(<App />, document.getElementById('root'));

myStore当中会有用@observable装饰的属性,?这些属性就是所谓“状态响应”的“状态”。

@inject

这个装饰器用于将MobX的数据源(通常是Store)注入到React组件中。然后你就可以访问Store的一部分或全部(看你注入了多少),使组件能够响应Store状态的变化。

结合Provider的示例代码,下面的示例是把Provider的myStore注入到了当前MyComponent的props中。即:当前MyComponent的props中的myStore和Provider的myStore一致。

注意:这里只使用了@inject注入,说明MyComponent可以主动读取myStore,但是当myStore发生变化的时候,MyComponent并不会被动收到通知去重新渲染。

@inject('myStore')
class MyComponent extends React.Component {
  render() {
    const { propDataFromParent } = this.props;

    return (
      <div>
        <p>Prop Data from Parent: {propDataFromParent}</p>
      </div>
    );
  }
}

?@observable

用于标记状态对象的属性,使其成为可观察的。被@observable标记的属性会被MobX追踪,当它们发生变化时,相关的观察者(使用@observer装饰器的组件)会得到通知并重新渲染。

import { observable } from 'mobx';

class MyStore {
  @observable someData: number = 42;
}

@observer

这个装饰器使React组件成为MobX的观察者(observer),以便在关联的状态发生变化时重新渲染组件。使用@observer装饰器可以让组件订阅相关状态的变化,并在变化时自动重新渲染

这个示例和上文@inject的代码示例的区别就是,该示例多了@observer,那么该示例就可以在myStore中的状态发生变化的时候,自动重新渲染。(具体状态变化和渲染的各种情况,下文会有解释,这里只需要了解observer是能够观察mobx中状态变化的。)

PS:组件会监听自己所有使用的@observable装饰的属性,包括组件内部自己声明的状态。

@inject('myStore')
@observer
class MyComponent extends React.Component {
  render() {
    const { propDataFromParent } = this.props;

    return (
      <div>
        <p>Prop Data from Parent: {propDataFromParent}</p>
      </div>
    );
  }
}

@action

用于标记修改状态的方法。在MobX中,任何改变状态的操作都应该在@action修饰的函数内部进行,以确保状态的一致性和可追踪性。

通过@inject注入到component中的myStore实例,实际上是只读的。也就是说不能在component中直接对myStore的值进行修改,而是使用@action装饰的myStore中的修改状态的方法。

import { action } from 'mobx';

class MyStore {
  @observable someData: number = 42;

  @action
  updateData(newData: number) {
    this.someData = newData;
  }
}

@computed

用于创建计算属性,这是一种从现有状态派生出的值,其值是根据其依赖的状态的变化而自动更新的。使用@computed装饰器可以创建派生状态,而不需要手动管理其更新逻辑。

这个应用的比较多的场景应该是各种计算之类的,例如组件实际使用的是x属性各种复杂运算之后的数据:

  1. 如果在渲染的时候才对其进行计算,那么每次渲染都需要重新进行复杂运算
  2. 如果使用@computed,那么在下一次渲染使用到这个值的时候,才会进行一次复杂运算返回,并缓存计算结果。后续渲染的时候重新取这个值,只要x属性没变化,将直接取缓存的计算结果。

由此可见,该装饰器在合适场景下能优化性能。

import { computed } from 'mobx';

class MyStore {
  @observable x: number = 10;
  @observable y: number = 20;

  @computed
  get sum(): number {
    return this.x + this.y;
  }
}

完整代码示例?

下面使用一个完整代码示例来梳理一下全文的知识点,可仔细看看注释。

Store:

import { observable, action, computed } from "mobx";

class MyStore {
  // 使用@observable装饰,那么
  // 当name、message发生变化的时候,观察了这两个属性的组件会自动重新渲染
  @observable name = "狗子";
  @observable message = "阿珍爱上了阿强";

  // 使用action装饰,说明该方法会引起状态变化
  // 观察可以看到该方法修改了message状态
  @action
  updateMessage(newMessage: string) {
    this.message = newMessage;
  }

  // 使用computed装饰,会自动重新计算值
  // 此方法:name改变或者message改变,都会引起wholeMessage改变
  @computed
  get wholeMessage() {
    return this.name + " 说: " + this.message;
  }
}

export default MyStore;

APP入口:

import { Provider } from "mobx-react";
import MyStore from "../../store/mystore";
import MyComponent from "../my-component";

const myStoreInstance = new MyStore();

const App = () => (
  // 使用Provider,将myStore提供给整个状态树。
  <Provider myStore={myStoreInstance}>
    <MyComponent />
  </Provider>
);

export default App;

?组件component:

import { inject, observer } from "mobx-react";
import React from "react";
import MyStore from "src/store/mystore";

interface Props {
  myStore?: MyStore;
}

// 用inject将Provider提供的myStore注入到MyComponent的Props中
@inject("myStore")
// 使用observer,则MyComponent会接收到myStore中,所有自己用到的状态改变的信息
@observer
class MyComponent extends React.Component<Props> {
  render() {
    const { myStore } = this.props;
    if (!myStore) {
      return (
        <div>
          <p>啥也没有a </p>
        </div>
      );
    }
    const { name, message } = myStore;

    return (
      <div>
        <p>name: {name}</p>
        <p>message: {message}</p>
        <p>wholeMessage: {myStore?.wholeMessage}</p>
        {/* {调用了updateMessage方法,修改了message值,同时导致整个组件重新渲染了。} */}
        <button onClick={() => myStore?.updateMessage("新消息来咯")}>
          发个新消息aaa?
        </button>
      </div>
    );
  }
}

export default MyComponent;

状态改变和渲染次数的疑惑

1. 在实际开发中,我有一个疑惑:是不是MyStore的任一属性改变,都会触发MyComponent的重新渲染呢?如果是的话,那当MyStore有较多属性,而MyComponent只用了一两个属性,不就可能会导致MyComponent发生很多不必要的渲染吗?

解答:MyComponent实际上观察的是自己在实际渲染过程中,用到的属性。也就是说当组件只用了a属性,那么当Store的b属性改变的时候,并不会引起组件的重新渲染。

2. 按照1的解答,只有用到的属性会改变会触发重新渲染,那么如果用到的属性没有用@observable装饰呢?

解答:如果没有用@observable装饰属性a,那么a改变不会触发重新渲染。但是,如果使用了@action装饰了修改a的方法,那么最后也会触发重新渲染。

最后

欢迎朋友们指正!

文章来源:https://blog.csdn.net/qq_43491495/article/details/135168138
本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。