【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) => {});
//...
相关推荐
NiNg_1_2344 分钟前
Echarts连接数据库,实时绘制图表详解
前端·数据库·echarts
如若12342 分钟前
对文件内的文件名生成目录,方便查阅
java·前端·python
滚雪球~1 小时前
npm error code ETIMEDOUT
前端·npm·node.js
沙漏无语2 小时前
npm : 无法加载文件 D:\Nodejs\node_global\npm.ps1,因为在此系统上禁止运行脚本
前端·npm·node.js
supermapsupport2 小时前
iClient3D for Cesium在Vue中快速实现场景卷帘
前端·vue.js·3d·cesium·supermap
brrdg_sefg2 小时前
WEB 漏洞 - 文件包含漏洞深度解析
前端·网络·安全
胡西风_foxww2 小时前
【es6复习笔记】rest参数(7)
前端·笔记·es6·参数·rest
m0_748254882 小时前
vue+elementui实现下拉表格多选+搜索+分页+回显+全选2.0
前端·vue.js·elementui
星就前端叭2 小时前
【开源】一款基于Vue3 + WebRTC + Node + SRS + FFmpeg搭建的直播间项目
前端·后端·开源·webrtc
m0_748234523 小时前
前端Vue3字体优化三部曲(webFont、font-spider、spa-font-spider-webpack-plugin)
前端·webpack·node.js