• redux太繁琐?一文入门学会使用mobx简化项目的状态管理


    一、mobx基本介绍

    mobx是一个简单、可扩展状态工具,相比redux,具有以下特点

    • 简洁、无模板代码(redux需要写大量模板代码)
    • 响应式数据,可直接修改(redux需要保证不可变)
    • 可直接处理异步(redux需要中间件处理异步)
    • 适合简单、规模不大的应用(redux约束强,更适合大型多人协作开发)

    :mobx6默认不开启修饰器语法

    二、mobx的使用

    1、搭建项目

    新建一个ts的react项目

    npx create-react-app my-app --template typescript
    
    • 1

    安装mobx库

    yarn add mobx mobx-react --save
    
    • 1

    :轻量级的mobx-react-lite只支持函数组件

    2、核心概念

    在这里插入图片描述

    • observable定义一个存储state的可追踪字段(Proxy)
    • action将一个方法标记为可以修改state的action
    • computed标记一个可以由state派生出新值并且缓存其输出的计算属性

    3、创建store

    以一个计数器为例,创建文件store/Counter.ts,新建一个Counter类,使用makeObservable方法将类的属性和方法变成响应式,并导出实例
    :mobx中的每一个store都应该只初始化一次

    // store/Counter.ts
    import {action, makeObservable, observable} from 'mobx'
    class Counter {
      constructor(){
        // 参数1:target,把谁变成响应式(可观察)
        // 参数2:指定哪些属性或者方法变成可观察
        makeObservable(this, {
           count: observable,
           increment: action,
           decrement: action,
           reset: action,
         })
      }
      count = 0
      increment(){
        this.count++
      }
      decrement(){
        this.count--
      }
      reset(){
        this.count = 0
      }
    }
    const counter = new Counter()
    export default counter 
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26

    在组件中使用,需要在App.tsx文件中引入store,即可使用其属性方法

    // App.tsx
    import counter from './store/Counter';
    // observer是一个高阶组件函数,需要包裹一个组件,这样组件才会更新
    import { observer } from 'mobx-react'
    
    function App() {
      const {cart, counter} = useStore()
      return (
        <div className="App">
          <h3>计数器案例</h3>
          <div>点击次数:{counter.count}</div>
          <button onClick={()c=> ounter.increment()}>1</button>
          <button onClick={()c=> ounter.decrement()}>1</button>
          <button onClick={() => counter.reset()}>重置</button>
        </div>
      );
    }
    export default observer(App);
    
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19

    4、this指向问题

    默认class中的方法不会绑定this,this指向取决于如何调用。Counter里面的方法的this没有绑定,因此需要通过箭头函数的形式使用

    <button onClick={()c=> ounter.increment()}>1</button>
    
    • 1

    要想直接使用,需要在Counter里面的makeObservable的使用通过action.bound绑定this的指向

        makeObservable(this, {
           count: observable,
           increment: action.bound,
           reset: action.bound,
         })
    
    • 1
    • 2
    • 3
    • 4
    • 5

    此时组件中即可直接使用store的方法

    <button onClick={counter.increment}>1</button>
    
    • 1

    5、计算属性

    mobx的computed可以用来从其他可观察对象中派生信息,具有以下特点:

    • 采用惰性求值,会缓存其输出,并且只有当其依赖的可观察对象被改变是才会重新计算
    • 其前面必须使用get进行修饰
    • 还需要通过makeObservable方法指定
      以double为例
    ...
        makeObservable(this, {
           count: observable,
           increment: action.bound,
           reset: action.bound,
           double: computed,
         })
    ...
    get double(){
      return this.count * 2
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11

    6、makeAutoObservable的使用

    makeAutoObservable是加强版的makeObservable,在默认情况下它将推断所有属性。推断规格如下:

    • 所有属性都成为observable
    • 所有方法都成为action
    • 所有的个体都成为computed
      可以通过第二个参数overrides排除不需要被观察的属性和方法,第三个参数autoBind可以绑定this指向
        // 参数1:target,把谁变成响应式(可观察)
        // 参数2:排除属性和方法
        // 参数3:指定自动绑定this
        makeAutoObservable(this, {}, {autoBind: true})
    
    • 1
    • 2
    • 3
    • 4

    三、mobx监听属性

    mobx中有两个监听方法autorun和reaction,其中:

    • autorun函数接受一个函数作为参数,在创建以及每当该函数所观察的值发生变化时,它都应该运行;mobx会自动收集并订阅所有可观察属性,一旦有改变发生,autorun将会再次触发
    autorun(() => {
       console.log('counter', counter.count);
    })
    
    • 1
    • 2
    • 3
    • reaction类似autorun,但在初始化时不会自动运行,且可以让你更加精细地控制要跟踪的可观察对象,其接受两个函数作为参数,参数1为data函数,其返回值将会作为第二个函数输入,参数2为回调函数
    reaction(
      () => counter.count,
      (newValue, oldValue) => {
        console.log('counter.count变化了');
      }
    )
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6

    四、异步处理

    异步进程在mobx中不需要任何特殊处理,因为不论是何时引发的所有reaction都将会自动更新,这是因为可观察对象是可变的,在action执行过程中保持对它们的引用一般是安全的。
    如果可观察对象的修改不是在action函数中,控制台会报警告,这是可以通过runInAction保证所有异步更新可观察对象步骤都标识为action

      incrementAsync(){
        setTimeout(() => {
          runInAction(() => {
            this.count++
          })
        }, 2000)
      }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7

    五、模块化

    mobx模块化管理即通过一个根store统一管理所有store
    在这里插入图片描述
    新建store/index.ts文件,导入所有store,使用useContext机制,自定义useStore hook,统一导出store

    import { useContext, createContext } from 'react'
    import cart from './Cart'
    import counter from './Counter'
    
    class RootStore {
      cart = cart
      counter = counter
    }
    const store = new RootStore()
    const Context = createContext(store)
    export const useStore = () => {
      return useContext(Context)
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13

    在App.tsx中统一导入,解构得到相应store

    import {useStore} from './store'
    ...
    	const {cart, counter} = useStore()
    ...
    
    • 1
    • 2
    • 3
    • 4

    文章完整代码地址:https://github.com/Stars-Chan/mobx-induction

    Refs: 【前端】三小时带你玩转mobx

  • 相关阅读:
    《CPU设计实战》第四章lab3记录找bug
    checksum校验和
    【云原生】docker+k8微服务容器化实战(下篇)
    杭电oj 2037 今年暑假不AC C语言
    代码随想录算法训练营day39
    Git常用命令
    SB30100LCT-ASEMI插件肖特基二极管SB30100LCT
    【Rust】Rust环境配置与语法基础
    230. 二叉搜索树中第K小的元素 java解决
    2020-java中级面试题
  • 原文地址:https://blog.csdn.net/weixin_44942126/article/details/126623007