mobx装饰器语法快速使用及 runInAction flow

1,284 阅读2分钟

mobx装饰器语法快速使用

1.安装准备

  • 安装mobx

    # mobx核心库
    npm install --save mobx
    # mobx绑定react
    npm install mobx-react --save
    
  • 安装Babel插件

    npm install @babel/plugin-proposal-decorators --save
    npm install @babel/plugin-proposal-class-properties --save
    
  • 当前安装的版本

    {
    	"mobx": "^6.5.0",
        "mobx-react": "^7.3.0",
    }
    

2.启用装饰器语法支持

  • package.json文件配置方式

    {
      "eslintConfig": {
        "parserOptions": {
          "ecmaFeatures": {
            "legacyDecorators": true
          }
        }
      },
       "babel": {
        "plugins": [
          [
            "@babel/plugin-proposal-decorators",
            {
              "legacy": true
            }
          ],
          [
            "@babel/plugin-proposal-class-properties",
            {
              "loose": true
            }
          ]
        ]
      }
    }
    

3.编写一个store状态仓库

  • 新建一个store文件夹

  • 新建index.js文件

    // index.js
    import { myStore } from "./myStore"; // 模块store状态库
    
    const store = {
      myStore,
    };
    
    export default store;
    
  • 新建模块store仓库

    // myStore.js
    import axios from "axios";
    import { observable, action, makeObservable, makeAutoObservable } from "mobx";
    
    class MyStore {
      @observable timer = "2020";
      @observable toDoList = [];
      @observable shopList = [];
    
      constructor() {
          // 捕获已经存在的对象属性并且使得它们可观察
        makeObservable(this);
      }
      @action add = (params) => {
        this.toDoList.push(params);
      };
    
      @action getList = () => {
        axios
          .get(
            'url'
          )
          .then((res) => {
            // 创建一个会被立即调用的临时 action。在异步进程中非常有用
            // 将状态修改代码包装成动作
            runInAction(() => {
              this.shopList = res.data.Data;
            });
          })
          .catch((err) => {
          });
      };
    }
    
    export const myStore = new MyStore();
    

4.store绑定到react

  • 入口文件index.js

    import React from "react";
    import { createRoot } from "react-dom/client";
    import App from "./App";
    import { Provider } from "mobx-react";
    import store from "./store";
    
    // 为提供的创建一个 React 根container并返回根。
    const root = createRoot(document.getElementById("root"));
    // 根可用于将 React 元素渲染到 DOM 中
    root.render(
      <Provider {...store}>
        <App />
      </Provider>
    );
    
    
  • 组件中使用store中内容

    // zujian.jsx
    import React, { Component } from "react";
    import { observer, inject } from "mobx-react";
    
    // inject:把store注入props中;observer使得组件可观察
    @inject("myStore")
    @observer
    class Home extends Component {
      constructor(props) {
        super(props);
        this.state = {};
      }
    
      componentDidMount() {
        let { myStore } = this.props;
        myStore.getList();
      }
      onChlickHandle = (type) => {
        let { myStore } = this.props;
        switch (type) {
          case "add":
                // 发起一个action
            myStore.add("内容");
            break;
          default:
            break;
        }
      };
    
      render() {
        // 获取store中的值  
        let { shopList } = this.props.myStore;
        return (
          <>
            <div>使用mobx</div>
            <div>{timer}</div>
            <button onClick={() => this.onChlickHandle("add")}>
              添加
            </button>
            <div>
              {shopList.map((item, i) => (
                <div key={i}>{item}</div>
              ))}
            </div>
          </>
        );
      }
    }
    export default Home;
    

5.一些问题

1.@observable 的数据存在不能在react组件中拿到和实时追踪更新?

  • 因为低版本的mobx的@observer观察组件方法的组件只追踪render函数中的数据存取,所以可以在render中获取store中的值;

    render() {
        // 获取store中的值  
        let { shopList } = this.props.myStore;
        return (
          <>
            <div>
              {shopList.map((item, i) => (
                <div key={i}>{item}</div>
              ))}
            </div>
          </>
        );
      }
    

2.异步action中存在请求响应回调没被action包裹成动作导致状态不能及时对应修改

// 异步action最佳解决方案
  getData = flow(function* () {
    try {
      const res = yield axios.get(
        "url"
      ); // 用 yield 代替 await
      console.log("getData", res);
      // 异步代码块会被自动包装成动作并修改状态
      this.projectsList = res.data.Data;
    } catch (error) {
      console.log("getData", err);
    }
  });