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

相关推荐
5980354152 小时前
【java工具类】小数、整数转中文小写
android·java·开发语言
superman超哥2 小时前
仓颉语言智能指针深度实战:突破 GC 与所有权的边界
c语言·开发语言·c++·python·仓颉
cike_y2 小时前
Mybatis之作用域(Scope)和生命周期-解决属性名和字段名不一致的问题&ResultMap结果集映射
java·开发语言·数据库·tomcat·mybatis
cypking2 小时前
解决 TypeScript 找不到静态资源模块及类型声明问题
前端·javascript·typescript
想学后端的前端工程师2 小时前
【Webpack构建优化实战指南:从慢到快的蜕变】
前端
IT_陈寒2 小时前
JavaScript性能优化:我用这7个V8引擎冷门技巧将页面加载速度提升了40%
前端·人工智能·后端
微爱帮监所写信寄信2 小时前
微爱帮监狱寄信写信小程序与焦作邮政系统对接技术方案
开发语言·网络协议·小程序·https·php·监狱寄信
澄江静如练_2 小时前
侦听器即watch
前端·javascript·vue.js
lsx2024062 小时前
适配器模式
开发语言