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

相关推荐
咚为几秒前
Rust tokio:Task ≠ Thread:Tokio 调度模型中的“假并发”与真实代价
开发语言·后端·rust
灰子学技术5 分钟前
性能分析工具比较pprof、perf、valgrind、asan
java·开发语言
摘星编程5 分钟前
React Native鸿蒙:Image本地图片显示
javascript·react native·react.js
Minilinux20189 分钟前
Google ProtoBuf 简介
开发语言·google·protobuf·protobuf介绍
大尚来也12 分钟前
看不见的加速器:深入理解 Linux 页缓存如何提升 I/O 性能
java·开发语言
wWYy.13 分钟前
程序编译链接过程
开发语言
局外人LZ15 分钟前
Uniapp脚手架项目搭建,uniapp+vue3+uView pro+vite+pinia+sass
前端·uni-app·sass
铁蛋AI编程实战16 分钟前
AI调用人类服务入门与Python实现(30分钟搭建“AI+真人”协作系统)
开发语言·人工智能·python
zhougl99617 分钟前
Java 常见异常梳理
java·开发语言·python
独自破碎E21 分钟前
已经 Push 到远程的提交,如何修改 Commit 信息?
开发语言·github