MobX

13 阅读4分钟

基本理论

通过 响应式编程 的方式管理应用状态。 思想:任何可以从应用状态中派生出来的值都应该自动派生

能力覆盖情况
基础原理响应式核心思想、三大核心概念(State/Actions/Derivations)
Store 构建类方式 / 函数方式创建 Store、makeAutoObservable 简化配置
核心响应式 APIObservable(状态)、Action(修改)、Computed(计算)、Reaction(副作用)
React 集成observer 高阶组件、多 Store 管理、Context Provider 模式
异步处理异步 Action、runInAction 批量更新(解决异步状态更新问题)
复杂状态支持嵌套 Observable、数组 / Map/Set 响应式操作
  1. State(状态) :应用的数据
  2. Actions(动作) :修改状态的操作
  3. Derivations(派生) :从状态中自动计算出的值(Computed)和副作用(Reactions)

数据流

44441412421412.png

基本使用

安装

npm install mobx mobx-react-lite
# 或使用 mobx-react(支持类组件)
npm install mobx mobx-react

创建 Store(类方式)

import { makeAutoObservable } from 'mobx'class CounterStore {
  count = 0
  
  constructor() {
    // makeAutoObservable 会自动将类的属性和方法转换为 observable 和 action
    makeAutoObservable(this)
  }
  
  increment() {
    this.count++
  }
  
  decrement() {
    this.count--
  }
  
  reset() {
    this.count = 0
  }
  
  // 计算属性(computed)
  get doubleCount() {
    return this.count * 2
  }
}
​
// 创建 store 实例
const counterStore = new CounterStore()
export default counterStore

创建 Store(函数方式)

import { makeAutoObservable } from 'mobx'function createCounterStore() {
  return makeAutoObservable({
    count: 0,
    increment() {
      this.count++
    },
    decrement() {
      this.count--
    },
    reset() {
      this.count = 0
    },
    get doubleCount() {
      return this.count * 2
    },
  })
}
​
const counterStore = createCounterStore()
export default counterStore

在组件中使用

import { observer } from 'mobx-react-lite'
import counterStore from './stores/counterStore'// observer 高阶组件使组件能够响应 observable 的变化
const Counter = observer(() => {
  return (
    <div>
      <button onClick={() => counterStore.decrement()}>-</button>
      <span>{counterStore.count}</span>
      <button onClick={() => counterStore.increment()}>+</button>
      <p>Double: {counterStore.doubleCount}</p>
    </div>
  )
})
​
export default Counter

核心 API

Observable(可观察状态)

Observable 是 MobX 的核心,用于创建可观察的状态。

import { observable, makeObservable } from 'mobx'class Store {
  count = 0
  name = 'MobX'
  
  constructor() {
    makeObservable(this, {
      count: observable,
      name: observable,
    })
  }
}

Action(动作)

Action 是修改状态的操作。MobX 要求所有修改状态的操作都应该在 action 中。

import { action, makeObservable } from 'mobx'class Store {
  count = 0
  
  constructor() {
    makeObservable(this, {
      count: observable,
      increment: action,
      decrement: action,
    })
  }
  
  increment() {
    this.count++ // 在 action 中修改状态
  }
  
  decrement() {
    this.count--
  }
}

Computed(计算值)

Computed 是从状态中自动计算出的值,只有当依赖的状态变化时才会重新计算。

import { computed, makeObservable } from 'mobx'class Store {
  count = 0
  
  constructor() {
    makeObservable(this, {
      count: observable,
      doubleCount: computed, // 计算属性
    })
  }
  
  get doubleCount() {
    return this.count * 2 // 自动追踪 count 的变化
  }
}

Reaction(副作用)

Reaction 是响应状态变化的副作用,如日志记录、网络请求等。

import { reaction, autorun, when } from 'mobx'// autorun:自动运行,立即执行一次
autorun(() => {
  console.log('Count changed:', store.count)
})
​
// reaction:响应特定状态变化
reaction(
  () => store.count, // 追踪的状态
  (count) => {
    console.log('Count is now:', count)
  }
)
​
// when:条件满足时执行
when(
  () => store.count > 10, // 条件
  () => {
    console.log('Count is greater than 10!')
  }
)

makeAutoObservable

makeAutoObservable 是最简单的方式,它会自动将类的属性和方法转换为 observable 和 action。

import { makeAutoObservable } from 'mobx'class Store {
  count = 0 // 自动变为 observable
  name = 'MobX' // 自动变为 observable
  
  increment() { // 自动变为 action
    this.count++
  }
  
  get doubleCount() { // 自动变为 computed
    return this.count * 2
  }
  
  constructor() {
    makeAutoObservable(this)
  }
}

在 React 中使用MobX

observer 高阶组件

observer 是 MobX 与 React 集成的核心,它使组件能够响应 observable 的变化。

import { observer } from 'mobx-react-lite'
import counterStore from './stores/counterStore'const Counter = observer(() => {
  return (
    <div>
      <span>{counterStore.count}</span>
      <button onClick={() => counterStore.increment()}>+</button>
    </div>
  )
})

使用多个 Store

import { observer } from 'mobx-react-lite'
import counterStore from './stores/counterStore'
import todoStore from './stores/todoStore'const App = observer(() => {
  return (
    <div>
      <Counter />
      <TodoList />
    </div>
  )
})

Provider 模式(可选)

MobX 也支持 Provider 模式,通过 Context 传递 store:

import { createContext, useContext } from 'react'
import { observer } from 'mobx-react-lite'
import counterStore from './stores/counterStore'const StoreContext = createContext(counterStore)
​
function App() {
  return (
    <StoreContext.Provider value={counterStore}>
      <Counter />
    </StoreContext.Provider>
  )
}
​
const Counter = observer(() => {
  const store = useContext(StoreContext)
  return <div>{store.count}</div>
})

异步操作

MobX 天然支持异步操作,无需额外配置:

import { makeAutoObservable, runInAction } from 'mobx'class UserStore {
  users = []
  loading = false
  error = null
  
  constructor() {
    makeAutoObservable(this)
  }
  
  async fetchUsers() {
    this.loading = true
    this.error = null
    
    try {
      const response = await fetch('/api/users')
      const users = await response.json()
      
      // 在异步操作中修改状态,需要使用 runInAction
      runInAction(() => {
        this.users = users
        this.loading = false
      })
    } catch (error) {
      runInAction(() => {
        this.error = error.message
        this.loading = false
      })
    }
  }
}

runInAction

runInAction 用于在异步操作中批量更新状态,确保所有更新都在同一个事务中:

import { runInAction } from 'mobx'

async function fetchData() {
  runInAction(() => {
    store.loading = true
    store.error = null
  })
  
  try {
    const data = await api.getData()
    runInAction(() => {
      store.data = data
      store.loading = false
    })
  } catch (error) {
    runInAction(() => {
      store.error = error.message
      store.loading = false
    })
  }
}

其他高级特性

嵌套 Observable

MobX 支持嵌套的 observable 对象和数组:

import { makeAutoObservable } from 'mobx'

class TodoStore {
  todos = []
  
  constructor() {
    makeAutoObservable(this)
  }
  
  addTodo(text) {
    this.todos.push({
      id: Date.now(),
      text,
      completed: false,
    })
  }
  
  toggleTodo(id) {
    const todo = this.todos.find(t => t.id === id)
    if (todo) {
      todo.completed = !todo.completed // 嵌套对象的属性也是 observable
    }
  }
}

数组操作

MobX 提供了 observable 数组,支持所有原生数组方法:

import { observable } from 'mobx'

const todos = observable([{ id: 1, text: 'Learn MobX' }])

// 所有数组操作都是响应式的
todos.push({ id: 2, text: 'Build app' })
todos[0].text = 'Learn MobX deeply'
todos.splice(0, 1)

Map 和 Set

MobX 也支持 observable Map 和 Set:

import { observable } from 'mobx'

const userMap = observable.map({})
userMap.set('user1', { name: 'John' })

const userIds = observable.set([1, 2, 3])
userIds.add(4)

自定义 Reaction

import { reaction } from 'mobx'

// 自定义 reaction,响应特定状态变化
const dispose = reaction(
  () => store.count, // 追踪的状态
  (count) => {
    console.log('Count changed to:', count)
    // 执行副作用
  }
)

// 清理 reaction
dispose()

补充

调试工具

import { enableLogging, trace } from 'mobx'

// 1. 开启 MobX 日志(仅开发环境)
if (process.env.NODE_ENV === 'development') {
  enableLogging({ level: 'info', name: 'TodoStore' })
}

class TodoStore {
  addTodo = (text) => {
    // 2. 追踪单个 Action 的状态变化
    trace(this, 'addTodo') 
    this.todos.push({ id: Date.now(), text, completed: false })
  }
}

// 3. Chrome 扩展:MobX DevTools(可视化监控 Observable/Action 变化)