【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) => {});
//...
相关推荐
乘风gg3 分钟前
AI coding 时代最值钱的东西,软件工程(下)
前端·ai编程·claude
用户114818678948413 分钟前
虚拟滚动与无限滚动的完整心法
前端
核验笔记的老王14 分钟前
前端表单防呆实践:如何排查自动填充导致的提交失败?
前端
用户4061220811114 分钟前
Vue vs React 核心差异全对比
前端
李纲明18 分钟前
微信小程序 web-view 打开空白或提示未配置业务域名:校验文件、HTTPS 与跳转域名排查
前端·微信小程序·https·web-view·小程序开发·业务域名
涛涛ing24 分钟前
一个框架为了“不水合”,把HTML注释都删了
前端
计算机魔术师1 小时前
AI渗透框架3小时破云,中国黑客组织正在升级打法
前端
蒲公英内测分发1 小时前
智能手环出海测试,海外合作方分散在不同国家,Android 测试包怎么持续分发和更新?
android·前端·人工智能·测试工具·智能手表
朱涛的自习室1 小时前
高价软件已死,我让 AI 开启了「平替计划」(Day 7 / 7)
android·前端·github
沙蒿同学1 小时前
Wails v3 实战:一个桌面提醒客户端,从 v2 升到 v3 的全过程
前端·后端·github