【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) => {});
//...
相关推荐
用户5757303346241 分钟前
🌟 从一行 HTML 到屏幕像素:浏览器是如何“画”出网页的?
前端
NEXT064 分钟前
React Hooks 进阶:useState与useEffect的深度理解
前端·javascript·react.js
sure2829 分钟前
React Native应用中使用sqlite数据库以及音乐应用中的实际应用
前端·react native
CHU72903510 分钟前
扭蛋机盲盒小程序前端功能设计解析:打造趣味与惊喜并存的消费体验
前端·小程序
前端布道师15 分钟前
Web响应式:列表自适应布局
前端
ZeroTaboo17 分钟前
rmx:给 Windows 换一个能用的删除
前端·后端
李剑一27 分钟前
Vue实现大屏获取当前所处城市及当地天气(纯免费)
前端
_果果然39 分钟前
这 7 个免费 Lottie 动画网站,帮你省下一个设计师的工资
前端
QT.qtqtqtqtqt40 分钟前
uni-app小程序前端开发笔记(更新中)
前端·笔记·小程序·uni-app
Aliex_git1 小时前
跨域请求笔记
前端·网络·笔记·学习