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

相关推荐
cui_ruicheng7 分钟前
Python从入门到实战(八):封装、多态与抽象类
开发语言·python
apihz8 分钟前
台风实时与历史详情查询免费 API 接口完整教程
android·开发语言·tcp/ip·dubbo·台风·天气预报
知无不研21 分钟前
c语言和c++中的静态关键字
开发语言·c++·静态关键字
品尚公益团队34 分钟前
C#在asp.net网页开发中的带cookie登录实现
前端·c#·asp.net
bksczm36 分钟前
Linux之信号量(POSIX标准)
java·开发语言
吠品1 小时前
PHP里取月份最后一天的几种方式
java·开发语言·eureka
CallmeFoureyes1 小时前
使用 C# 提取 Word 文档中的表格数据
开发语言·c#·word
gugucoding1 小时前
2. 【Java】搭建Java开发环境
java·开发语言
多加点辣也没关系1 小时前
JavaScript|第9章:对象 — 基础
开发语言·javascript·ecmascript
2601_949818091 小时前
Vector从入门到应用(C++ STL动态数组万字全解
开发语言·c++