Mobx6集成React和Typescript实践应用

1,006 阅读3分钟

前言

先来看看Mobx官方对其描述:MobX 是一个身经百战的库,它通过运用透明的函数式响应编程(Transparent Functional Reactive Programming,TFRP)使状态管理变得简单和可扩展。

Mobx与Redux都是非常优秀的React状态管理方案,对于这两个状态管理方案的优点与不同,在此不做详细对比,此文主要基于Mobx6集成React和Typescript在项目中具体的使用方式进行说明。

Mobx6相比于Mobx5Mobx4在具体的使用方式上都有很大的不同,在 MobX 6 中不推荐使用装饰器语法,因为它不是 ES 标准,并且标准化过程要花费很长时间,但是通过配置仍然可以启用装饰器语法。

初始化React工程

本案例采用create-react-app来快速创建react与typescript的环境。需要安装依赖如下:

  • mobx
  • mobx-react或者mobx-react-lite
  1. 创建store目录

src目录下新建mobxStore文件夹,并依次创建index.ts,timer.ts,user.ts文件。

// timer.ts
import { makeAutoObservable } from 'mobx';
// 定义timer数据领域接口
export interface TimerStoreType {
  timer: number;
  addTimer: Function;
  resetTimer: Function;
}
class TimerStore implements TimerStoreType {
  timer = 0;
  constructor() {
    // mobx6的不同,函数式,而不再通过使用装饰器
    makeAutoObservable(this);
  }

  addTimer() {
    this.timer += 1;
  }

  resetTimer() {
    this.timer = 0;
  }
}

export { TimerStore };

// user.ts
import { makeObservable, observable, computed, action } from 'mobx';
// 定义user数据领域store接口
export interface UserStoreType {
  name: string;
  age: number;
  doubleAge: number;
  editName: (str: string) => void;
}

class UserStore {
  name = '张三';
  age = 18;
  get doubleAge() {
    return this.age * 2;
  }
  constructor() {
    // makeObservable需要手动注解
    makeObservable(this, {
      name: observable,
      age: observable,
      doubleAge: computed,
      editName: action,
    });
  }

  editName(str: string) {
    this.name = str;
  }
}

export { UserStore };

// index.ts
import { createContext } from 'react';
import { TimerStore, TimerStoreType } from './timer';
import { UserStore, UserStoreType } from './user';
// 单一Store类型,class组件props需要
export type { TimerStoreType, UserStoreType };

// root store mobx-react Provider 使用
export const stores = {
  timerStore: new TimerStore(),
  usertore: new UserStore(),
};

// root store fn组件 useContext使用
export const useStore = createContext(stores);

  1. react根应用基于context模式提供store
// 入口文件 index.tsx

import React from 'react';
import ReactDOM from 'react-dom';
import './index.css';
import AppMobx from './AppMobx';

import { Provider } from 'mobx-react';
import { stores } from './mobxStore/index';
import reportWebVitals from './reportWebVitals';

ReactDOM.render(
  <React.StrictMode>
    <Provider {...stores}>
      <AppMobx></AppMobx>
    </Provider>
  </React.StrictMode>,
  document.getElementById('root')
);
reportWebVitals();
// AppMobx.tsx
import React from 'react';
// class 组件使用demo
import ClassPage from './pages/MobxDemo/ClassPage';
// function组件使用demo
import FnPage from './pages/MobxDemo/FnPage';
function AppMobx() {
  return (
    <div>
      <h3>mobx class组件用法</h3>
      <ClassPage></ClassPage>
      <hr />
      <h3>mobx function组件用法</h3>
      <FnPage></FnPage>
    </div>
  );
}
export default AppMobx;
  1. 组件中使用sotre数据

class组件使用demo,其中,class组件的使用又可以分为函数式用法和装饰器用法,首先来看类组件中的装饰器用法,注意,如需使用装饰器,需要进行启用配置

import React from 'react';
import { observer, inject } from 'mobx-react';
import { TimerStoreType } from '../../mobxStore/index';
// props需要声明
interface IProps {
  // timer数据域
  timerStore?: TimerStoreType;
}
interface IState {}
@inject('timerStore')
@observer
class ClassPage extends React.Component<IProps, IState> {
  constructor(props: IProps) {
    super(props);
    this.addMobx = this.addMobx.bind(this);
    this.resetMobx = this.resetMobx.bind(this);
    this.state = {};
  }
  addMobx() {
    this.props.timerStore?.addTimer();
  }
  resetMobx() {
    this.props.timerStore?.resetTimer();
  }
  render() {
    const { timerStore } = this.props;
    return (
      <div>
        <p>当前timer值:{timerStore?.timer}</p>
        <button onClick={this.addMobx}>mobx值+1</button>
        <button onClick={this.resetMobx}>重置</button>
      </div>
    );
  }
}
export default ClassPage;

class组件的函数式用法如下:

import React from 'react';
import { observer, inject } from 'mobx-react';
import { TimerStoreType } from '../../mobxStore/index';
interface IProps {
  timerStore?: TimerStoreType;
}
interface IState {}
class ClassPage extends React.Component<IProps, IState> {
  constructor(props: IProps) {
    super(props);
    this.addMobx = this.addMobx.bind(this);
    this.resetMobx = this.resetMobx.bind(this);
    this.state = {};
  }
  addMobx() {
    this.props.timerStore?.addTimer();
  }
  resetMobx() {
    this.props.timerStore?.resetTimer();
  }
  render() {
    const { timerStore } = this.props;
    return (
      <div>
        <p>当前timer值:{timerStore?.timer}</p>
        <button onClick={this.addMobx}>mobx值+1</button>
        <button onClick={this.resetMobx}>重置</button>
      </div>
    );
  }
}
// 重点在这里
// inject注入timerStore
export default inject('timerStore')(observer(ClassPage));

function组件使用参考如下:

import React, { useContext } from 'react';

import { observer } from 'mobx-react';
// 单独引入需要数据域store
import { useStore } from '../../mobxStore/index';

interface IProps {}

const FnPage: React.FC = (props: IProps) => {
  // hook useContext
  const { timerStore } = useContext(useStore);
  return (
    <div>
      <p>当前timer值:{timerStore.timer}</p>
      <button onClick={() => timerStore.addTimer()}>mobx值+1</button>
      <button onClick={() => timerStore.resetTimer()}>重制</button>
    </div>
  );
};
export default observer(FnPage);

总结

此文只是仅仅介绍了Mobx6集成React和Typescript的使用案例说明,供有需要了解的同学们参考。下篇文章会对mobx和mobx-react两个模块的核心api进行源码的分析,只要了解了源码的实现,我们才能在具体的项目中更好的使用mobx来进行状态管理。