学习mobx的第一天

169 阅读2分钟

1. 安装

# mobx核心库
npm install --save mobx

# mobx绑定react
npm install mobx-react --save

2. 兼容装饰器语法

安装下面的插件

npm install @babel/plugin-proposal-decorators --save
npm install @babel/plugin-proposal-class-properties --save

3. 配置

  1. vite.config.js
import { defineConfig } from 'vite'
import react from '@vitejs/plugin-react'

// https://vitejs.dev/config/
export default defineConfig({
  plugins: [react({
    babel: {
      plugins: [
        ["@babel/plugin-proposal-decorators", { legacy: true }],
        ["@babel/plugin-proposal-class-properties", { loose: true }]
      ]
    }
  })],
})
  1. jsconfig.json(没有的话,新建一个)
{
  "compilerOptions":{
      "experimentalDecorators": true
  }
}
  1. eslint 可能也会报错,自己修改一下

3. 项目结构截图

image.png

4. 上代码

  1. userStore.js
import { observable, computed, action, makeObservable, runInAction } from "mobx";
import axios from "axios";
class UserInfo {
  // Observable 值可以是JS基本数据类型、引用类型、普通对象、类实例、数组和映射
  @observable name = 'zrs'
  @observable sex = '男'
  @observable age = 20
  @observable hobbys = ['羽毛球', '游戏']

  constructor() {
    // 捕获已经存在的对象属性并且使得它们可观察
    makeObservable(this);
  }

  @computed get getHobbys() {
    return this.hobbys
  }

  @action addHobby(val) {
    this.hobbys = [...this.hobbys, val]
    console.log("this", this.hobbys);
  }

  @action delHobby(val) {
    console.log(val);
    this.hobbys = this.hobbys.filter(it => it !== val)
  }
  @action getHobbyList = () => {
    axios
      .get(
        'url'
      )
      .then((res) => {
        // 创建一个会被立即调用的临时 action。在异步进程中非常有用
        // 将状态修改代码包装成动作
        runInAction(() => {
          this.hobbys = res.data;
        });
      })
      .catch((err) => {
      });
  };

}

const userInfo = new UserInfo()

export default { userInfo }
  1. main.jsx
import React from 'react'
import ReactDOM from 'react-dom/client'
import App from './App.jsx'
import store from './store/userStore.js'
import { Provider } from 'mobx-react'

ReactDOM.createRoot(document.getElementById('root')).render(
  <React.StrictMode>
    <Provider {...store}>
      <App />
    </Provider>
  </React.StrictMode>
)
  1. app.jsx
import React, { Component } from 'react'
import { inject, observer } from 'mobx-react'
import Child1 from './components/child1'
import Child2 from './components/child2'

@inject('userInfo')
@observer
export default class App extends Component {
  constructor() {
    super()
    this.state = {
      hobby: ''
    }
  }
  render() {
    console.log('userInfo', this.props.userInfo)
    const { name, age, getHobbys } = this.props.userInfo
    return (
      <div>
        <h1>app</h1>
        {name}--------------{age}
        <input
          type="text"
          value={this.state.hobby}
          onInput={(e) => {
            this.setState({
              hobby: e.target.value
            })
          }}
        />
        <button
          onClick={() => {
            console.log('this.state.hobby', this.state.hobby)
            this.props.userInfo.addHobby(this.state.hobby)
            this.setState({ hobby: '' })
          }}
        >
          确认
        </button>
        <ul>
          {getHobbys.map((it) => (
            <li key={it}>
              {it}-----------
              <button
                onClick={() => {
                  store.userInfo.delHobby(it)
                }}
              >
                删除
              </button>
            </li>
          ))}
        </ul>
        <hr />
        <h1>child1</h1>
        <Child1 />
        <hr />
        <h1>child2</h1>
        <Child2 />
      </div>
    )
  }
}

参考文章:mobx装饰器语法快速使用及 runInAction flow - 掘金 (juejin.cn)

  1. child1.jsx
import React, { Component } from 'react'
import { observer } from 'mobx-react'
import store from '../store/userStore'

@observer
export default class child1 extends Component {
  render() {
    return (
      <div>
        <ul>
	  {/* 计算属性的使用 */}
          {store.userInfo.getHobbys.map((it) => (
            <li key={it}>
              {it}-----------
              <button
                onClick={() => {
                  store.userInfo.delHobby(it)
                }}
              >
                删除
              </button>
            </li>
          ))}
        </ul>
      </div>
    )
  }
}
  1. child2.jsx
import React, { Component } from 'react'

export default class child2 extends Component {
  render() {
    return <div>child2</div>
  }
}

5. 一些有用的东西

1. makeAutoObservable 和 makeObservable

参考文章:MobX 学习 - 03 makeAutoObservable 和 makeObservable_皮蛋很白的博客-CSDN博客

2.异步

参考文章:mobx装饰器语法快速使用及 runInAction flow - 掘金 (juejin.cn)

// 异步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);
    }
  });

3.其他

  1. Mobx里启用严格模式的函数就是useStrict,注意和原生JS的"use strict"不是一个东西。如果设置成严格模式,则只有@action才可以修改观测中的值。
  1. action只能影响当前运行的函数,而不能影响函数中的异步回调函数,因此需要对异步回调函数也使用action标注。如果是用async function,则可以使用runInAction函数来解决。