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

相关推荐
李慕婉学姐19 小时前
【开题答辩过程】以《基于Java的周边游优选推荐网站的设计与实现》为例,不知道这个选题怎么做的,不知道这个选题怎么开题答辩的可以进来看看
java·开发语言
Two_brushes.19 小时前
Cmake中寻库文件的路径
开发语言·c++·cmake
Larry_Yanan19 小时前
Qt安卓开发(三)双摄像头内嵌布局
android·开发语言·c++·qt·ui
wjs202419 小时前
Kotlin 条件控制
开发语言
我命由我1234519 小时前
Kotlin 开发 - Kotlin Lambda 表达式返回值
android·java·开发语言·java-ee·kotlin·android studio·android-studio
生活在一步步变好i19 小时前
前端加载优化核心知识点详解
前端
雨中散步撒哈拉19 小时前
22、做中学 | 高一下期 | Golang反射
开发语言·golang·状态模式
a努力。19 小时前
中国电网Java面试被问:Dubbo的服务目录和路由链实现
java·开发语言·jvm·后端·面试·职场和发展·dubbo
2501_9481953419 小时前
RN for OpenHarmony英雄联盟助手App实战:关于实现
javascript·react native·react.js
C_心欲无痕20 小时前
理解前端的运行时与编译时
前端