You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何在Mobx的Observable数组更新时自动触发副作用?

解决Mobx Observable数组更新时自动触发保存函数的问题

嘿,作为Mobx新手碰到这种需求太正常啦!不用在每个更新数组的函数里手动加保存逻辑,用Mobx的reaction或者autorun就能轻松实现自动触发~我给你详细讲讲怎么用:

一、推荐用reaction:精准监听数组变化

reaction是Mobx里专门用来监听依赖变化并执行回调的工具,它只会在依赖值实际变化时触发,非常适合你的场景。

实现步骤:

  1. 在你的Store类的构造函数里初始化reaction
  2. 第一个参数返回你要监听的依赖(这里就是Todos数组的内容)
  3. 第二个参数是依赖变化时要执行的保存逻辑

代码示例:

import { observable, action, reaction } from 'mobx'

class TodoStore {
  @observable Todos = []
  // 假设你的用户ID存在这里,也可以设为observable如果会动态变化
  userId = 'your-user-id'

  constructor() {
    // 监听Todos数组的内容变化
    reaction(
      // 第一个函数:返回需要监听的依赖值
      // 用展开运算符生成新数组,确保数组内容/长度变化时能被捕获
      () => [...this.Todos],
      // 第二个函数:依赖变化时执行的回调
      (newTodos) => {
        // 调用你的数据库保存函数
        UpdateDbData(this.userId, newTodos)
      }
    )
  }

  @action addTodo(todo, important) {
    const newTodo = { 
      id: Math.random(), 
      text: todo, 
      isImportant: important, 
      completed: false, 
      date: Date.now() 
    }
    this.Todos.push(newTodo)
  }

  @action removeTodo(todoId) {
    this.Todos = this.Todos.filter(todo => todo.id !== todoId)
  }

  // 其他修改Todos的action...
}

// 你的数据库更新函数
const UpdateDbData = (id, newTodos) => {
  firebase.database().ref(`users/${id}`).update({ todos: newTodos })
    .catch(error => console.log(error))
}

关键说明:

  • 为什么用[...this.Todos]?因为Mobx的observable数组是特殊对象,直接返回this.Todos的话,reaction只会检测数组引用的变化(比如重新赋值this.Todos = []),而push、splice这类修改数组内容的操作不会触发。展开成新数组后,只要数组里的元素或长度变化,就会被检测到。
  • 如果你的userId是动态变化的(比如登录后才获取),记得把userId也设为@observable,并在依赖函数里包含它:
    @observable userId = ''
    
    reaction(
      () => ({ todos: [...this.Todos], userId: this.userId }),
      ({ todos, userId }) => {
        // 确保userId存在再执行保存
        if (userId) UpdateDbData(userId, todos)
      }
    )
    

二、用autorun:自动追踪所有用到的Observable

autorun会自动追踪函数内部用到的所有observable值,只要其中任何一个变化就会触发,而且初始化时会自动执行一次。

代码示例:

import { observable, action, autorun } from 'mobx'

class TodoStore {
  @observable Todos = []
  userId = 'your-user-id'

  constructor() {
    autorun(() => {
      // 这里用到了this.Todos,所以它变化时就会执行
      const currentTodos = [...this.Todos]
      UpdateDbData(this.userId, currentTodos)
    })
  }

  // 其他action和函数...
}

两者对比:

  • 如果希望页面初始化时就把现有Todos保存到数据库,用autorun
  • 如果只希望在Todos变化时触发保存,初始化不执行,用reaction(如果需要初始化也执行,可以给reaction加第三个参数{ fireImmediately: true })

最后注意

确保所有修改Todos的操作都放在@action装饰的函数里,这是Mobx的最佳实践,能保证状态更新的可追踪性和性能。

内容的提问来源于stack exchange,提问作者Maël.L

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.05.29 07:13:47