【React】MobX

概述

mobx 实现像 vue 一样声明式的修改数据,我们在项目中直接使用 mobx + mobx-react 。

mobxjs/mobx-react: React bindings for MobX (github.com)

https://zh.mobx.js.org/the-gist-of-mobx.html

  • state 数据

  • action 动作

  • derivation 派生

    • computed
    • observer 监听变化,包裹的 React 组件
    • autorun 监听变化,像 watch

computed 必须是纯函数。而 action 可以修改 state (如 arr.push) 。

computed 采用惰性求值,会缓存其输出,并且只有当其依赖的可观察对象被改变时才会重新计算。 它们在不被任何值观察时会被暂时停用。

shell 复制代码
npm install mobx-react mobx --save

使用

tsx 复制代码
import React, {FC, useEffect} from 'react';
import {action, makeAutoObservable, makeObservable, observable} from "mobx";
import {observer} from "mobx-react";

class Timer {
    secondsPassed = 0;

    constructor() {
        // 使该类的所有属性变成响应式(自动)
        // makeAutoObservable(this)
        // 使该类的所有属性变成响应式(手动)
        makeObservable(this, {
            secondsPassed: observable,
            increment: action,
            reset: action
        })
    }

    increment(count:number) {
        this.secondsPassed += count;
    }

    reset() {
        this.secondsPassed = 0;
    }
}

const myTimer = new Timer()

type PropsType = { timer: Timer }
const TimerView = observer((props: PropsType) => {
    const {timer} = props
    return <button onClick={() => timer.reset()}>
        seconds passed : {timer.secondsPassed}
    </button>
})

const BasicDemo: FC = () => {
    useEffect(() => {
        const id = setInterval(() => myTimer.increment(10), 1000);
        return () => clearInterval(id);
    }, []);
    return <div>
        <p>Basic Demo</p>
        <TimerView timer={myTimer}/>
    </div>
}

export default BasicDemo;

案例

index.tsx

tsx 复制代码
<TodoList store={store}/>

store.ts

ts 复制代码
import { nanoid } from 'nanoid'
import { makeObservable, observable, action, computed } from 'mobx'

// Todo class
export class ObservableTodoStore {
    id = ''
    task = ''
    completed = false

    constructor(task: string) {
        makeObservable(this, {
            id: observable,
            task: observable,
            completed: observable,
            rename: action,
            toggleCompleted: action
        })

        this.id = nanoid(5)
        this.task = task
    }

    rename(newName: string) {
        this.task = newName
    }

    toggleCompleted() {
        this.completed = !this.completed
    }
}

// TodoList class
export class ObservableTodoListStore {
    todos: ObservableTodoStore[] = []

    constructor() {
        makeObservable(this, {
            todos: observable,
            completedTodosCount: computed, // 计算
            addTodo: action,
            removeTodo: action
        })
    }

    // get(用于计算,不用于修改) 获取已经完成的 todos 数量
    get completedTodosCount() {
        return this.todos.filter(t => t.completed).length
    }

    addTodo(task: string) {
        const newTodo = new ObservableTodoStore(task)
        this.todos.push(newTodo) // 声明式,像 Vue
    }

    removeTodo(id: string) {
        const index = this.todos.findIndex(t => t.id === id)
        this.todos.splice(index, 1)
    }
}

const store = new ObservableTodoListStore()
export default store

TodoList.tsx

tsx 复制代码
//...
type PropsType = {
    store: ObservableTodoListStore
}
const TodoList: FC<PropsType> = observer((props: PropsType) => {});
//...
相关推荐
假客套6 分钟前
2025 后端自学UNIAPP【项目实战:旅游项目】7、景点详情页面【完结】
前端·uni-app·旅游
程序员小张丶18 分钟前
基于React Native开发HarmonyOS 5.0主题应用技术方案
javascript·react native·react.js·主题·harmonyos5.0
Captaincc20 分钟前
Ilya 现身多大毕业演讲:AI 会完成我们能做的一切
前端·ai编程
teeeeeeemo32 分钟前
Vue数据响应式原理解析
前端·javascript·vue.js·笔记·前端框架·vue
Sahas101936 分钟前
__VUE_PROD_HYDRATION_MISMATCH_DETAILS__ is not explicitly defined.
前端·javascript·vue.js
Jinxiansen02111 小时前
Vue 3 实战:【加强版】公司通知推送(WebSocket + token 校验 + 心跳机制)
前端·javascript·vue.js·websocket·typescript
MrSkye1 小时前
React入门:组件化思想?数据驱动?
前端·react.js·面试
BillKu1 小时前
Java解析前端传来的Unix时间戳
java·前端·unix
@Mr_LiuYang1 小时前
网页版便签应用开发:HTML5本地存储与拖拽交互实践
前端·交互·html5·html5便签应用
JacksonGao1 小时前
一分钟带你了解React Fiber的工作单元结构!
前端·react.js