mobx相关使用及源码实现

用于合并多个mobx的store工具函数

关键点:

使用 Object.defineProperty 定义 getter

懒加载:只有第一次访问 store.user 时,才会 new UserStore()

单例:之后每次访问都返回同一个实例

js 复制代码
// 用来合并多个store
export interface StoreConstructor<T> {
  new (): T;
}

export type InstanceForEach<T extends Record<string, StoreConstructor<any>>> = {
  [P in keyof T]: InstanceType<T[P]>;
};

export function lazyCreateStore<U, T>(
  store: U,
  key: keyof U,
  ctr: StoreConstructor<T>
) {
  let _instance: T = null as T;
  Object.defineProperty(store, key, {
    configurable: false,
    enumerable: true,
    get() {
      if (!_instance) {
        _instance = new ctr();
      }
      return _instance;
    },
    set() {
      /** noop */
    },
  });
}

export const createStore = <T extends Record<string, StoreConstructor<any>>>(
  storeClasses: T
) => {
  const _store: InstanceForEach<T> = {} as InstanceForEach<T>;
  Object.keys(storeClasses).forEach((key) => {
    lazyCreateStore(_store, key as keyof T, storeClasses[key]);
  });
  (window as any).store = _store;
  return _store;
};

创建两个store

js 复制代码
//count.ts
import { makeObservable, observable, action } from "mobx";
export class CountStore {
  num = 0;
  constructor() {
    makeObservable(this, {
      num: observable,
      add: action,
    });
  }
  add = () => {
    this.num++;
  };
}
js 复制代码
// todoStore.ts
import { makeObservable, observable, action, computed } from "mobx";
export type Todo = {
  task: string;
  completed: boolean;
  assignee: null | string;
};

export type TodoList = Todo[];

export class TodoStore {
  todoList: TodoList = [
    {
      task: "喝水",
      completed: false,
      assignee: null,
    },
  ];

  constructor() {
    makeObservable(this, {
      todoList: observable,
      addTodo: action,
      editTodo: action,
      completedTodoCount: computed,
      report: computed,
    });
  }

  addTodo = (task: string) => {
    this.todoList.push({
      task,
      completed: false,
      assignee: null,
    });
  };

  // 返回完成的任务数
  get completedTodoCount() {
    return this.todoList.filter((todo) => todo.completed === true).length;
  }

  editTodo = (index: number, todo: Todo) => {
    this.todoList[index] = todo;
  };

  get report() {
    if (this.todoList.length === 0) {
      return "无";
    }

    const nextTodo = this.todoList.find((todo) => todo.completed === false);

    return `下一个待办"${nextTodo?.task}"。进度${this.completedTodoCount}/${this.todoList.length}`;
  }
}

导出

js 复制代码
// store/index.ts
import { createStore } from "./util";
import { CountStore } from "./Count";
import { TodoStore } from "./TodoStore";

const storeClasses = {
  count: CountStore,
  todo: TodoStore,
};

export const store = createStore(storeClasses);

页面上使用

js 复制代码
import { observer } from "../which";
import { store } from "../store";
import { Todo } from "../store/TodoStore";

const TodoListPage = observer(() => {
  const addNewTodo = () => {
    store.todo.addTodo(prompt("输入新的待办任务", "来杯水"));
  };

  return (
    <div>
      <h1>TodoListPage</h1>
      <button onClick={addNewTodo}>新增任务</button>
      <p>完成了{store.todo.completedTodoCount}个任务</p>

      <p>{store.todo.report}</p>
      <ul>
        {store.todo.todoList.map((todo, index) => (
          <TodoView key={index} todo={todo} index={index} />
        ))}
      </ul>
    </div>
  );
});

const TodoView = observer(({ todo, index }: { todo: Todo; index: number }) => {
  return (
    <li
      className="card"
      onDoubleClick={() =>
        store.todo.editTodo(index, {
          ...todo,
          task: prompt("任务名称", todo.task) || todo.task,
        })
      }
    >
      <input
        type="checkbox"
        checked={todo.completed}
        onChange={() =>
          store.todo.editTodo(index, { ...todo, completed: !todo.completed })
        }
      />
      {todo.task}
    </li>
  );
});

export default TodoListPage;

mobx源码实现 todo...

  1. 首先函数组件用到的包
    mobx 和 mobx-react-lite(专注于函数组件,体积较小)
    常见api
js 复制代码
import {
  makeAutoObservable,
  makeObservable,
  observable,
  action,
  computed,
  Reaction,
  AnnotationsMap,
  runInAction,
  autorun,
  Provider,
  inject,
} from "mobx";

runInAction:用来在异步操作后修改状态。

autorun:监听状态变化并自动执行副作用 类似于vue中的watch

相关推荐
艾莉丝努力练剑1 分钟前
【QT】Qt常用控件与布局管理深度解析:从原理到实践的架构思考
linux·运维·服务器·开发语言·网络·qt·架构
杜子不疼.2 分钟前
用 Python 实现 RAG:从文档加载到语义检索全流程
开发语言·人工智能·python
chao1898443 分钟前
基于改进二进制粒子群算法的含需求响应机组组合问题MATLAB实现
开发语言·算法·matlab
lcj25113 分钟前
字符函数,字符串函数,内存函数
c语言·开发语言·c++·windows
独特的螺狮粉4 分钟前
古诗词飞花令随机出题小助手:鸿蒙Flutter框架 实现的古诗词游戏应用
开发语言·flutter·游戏·华为·架构·开源·harmonyos
cch89187 分钟前
C++、Python与汇编语言终极对比
java·开发语言·jvm
Chockmans9 分钟前
2026年3月青少年软件编程(Python)等级考试试卷(六级)
开发语言·python·青少年编程·蓝桥杯·pycharm·python3.11·python六级
Python大数据分析@11 分钟前
使用Python和亮数据采集器搭建专利查询GUI系统
开发语言·python
格林威13 分钟前
Linux系统工业相机:Linux udev 规则绑定相机设备
linux·运维·开发语言·人工智能·数码相机·计算机视觉·工业相机
XMYX-013 分钟前
04 - Go 的变量和常量:零值、类型推导与枚举
开发语言·golang