我用 Zustand 三年了,直到遇见 easy-model...

不是说Zustand不好,而是有些场景它真的hold不住。

故事是这样的

我们公司有个中后台项目,状态管理一直用Zustand。讲真,Zustand确实香------API简洁、性能好、类型推断也还行。

直到有一天,产品经理提了一个需求:

"做一个操作日志中心,用户每做一个操作就记录下来,支持撤销重做。而且要能在列表页看到嵌套对象的变化轨迹。"

我自信满满地开始写,然后就被打脸了。

Zustand的痛点

1. 状态一多就成了"函数大杂烩"

tsx 复制代码
// store.ts
const useStore = create((set, get) => ({
  user: null,
  orders: [],
  filters: {},
  pagination: { page: 1, size: 10 },
  loading: false,

  setUser: (user) => set({ user }),
  setOrders: (orders) => set({ orders }),
  setFilters: (filters) => set({ filters }),
  setPagination: (pagination) => set({ pagination }),
  setLoading: (loading) => set({ loading }),

  fetchOrders: async () => {
    const { filters, pagination } = get();
    set({ loading: true });
    const res = await api.getOrders(filters, pagination);
    set({ orders: res.data, loading: false });
  },

  // ... 200行后
}));

一个文件写了500行,到后面自己都不想看了。

2. 撤销重做?自己实现吧

Zustand没有内置history支持。网上倒是有zundo这种中间件,但:

  • 配置繁琐
  • 类型推断经常出问题
  • 和业务代码集成麻烦

3. 监听嵌套对象?不好意思,做不到

tsx 复制代码
const orders = useStore((s) => s.orders);
// 改变了 orders[0].items[0].price
// 组件不会更新!因为引用没变

你得用subscribe或者自己写selector,关键是一旦嵌套深了,selector写得怀疑人生。

然后我发现了easy-model

tsx 复制代码
// 用类来组织,一个领域一个类
class OrderModel {
  orders: Order[] = [];
  filters: FilterParams = {};
  pagination = { page: 1, size: 10 };
  loading = false;

  async fetchOrders() {
    this.loading = true;
    const res = await api.getOrders(this.filters, this.pagination);
    this.orders = res.data;
    this.loading = false;
  }

  setFilter(key: string, value: any) {
    this.filters[key] = value;
  }
}

// 内置history支持
const order = useModel(OrderModel, []);
const history = useModelHistory(order);

// 撤销重做,一行搞定
history.back();
history.forward();
history.reset();

这才是面向对象!

深度监听,真香

tsx 复制代码
class ComplexModel {
  user = {
    profile: {
      address: { city: "北京" },
    },
  };
  orders = [];
}

// 监听嵌套对象变化
watch(user, (keys, prev, next) => {
  // keys: ['profile', 'address', 'city']
  console.log("变化了", keys, prev, next);
});

user.profile.address.city = "上海";
// 自动触发监听,拿到完整的变化路径

还有IoC?

tsx 复制代码
// 定义依赖
const apiSchema = object({
  baseUrl: string(),
}).describe("API配置");

// 注入
class OrderApi {
  @inject(apiSchema)
  config?: { baseUrl: string };

  async getOrders() {
    return fetch(`${this.config?.baseUrl}/orders`);
  }
}

// 配置
config(
  <Container>
    <CInjection
      schema={apiSchema}
      ctor={OrderApi}
      params={["https://api.example.com"]}
    />
  </Container>,
);

这不妥妥的企业级架构?

性能对比

官方benchmark(10万个元素,5轮批量更新):

方案 耗时
Zustand 0.6ms
easy-model 3.1ms
MobX 16.9ms
Redux 51.5ms

easy-model比Zustand慢3倍,但换来了:

  • 类模型组织方式
  • 内置IoC能力
  • 深度监听
  • History支持

这波不亏!

怎么选?

  • 小项目、简单状态 → Zustand依旧真香
  • 中大型、需要领域模型、需要IoC、需要history → easy-model真香

Github: github.com/ZYF93/easy-...

觉得有帮助的点个⭐️支持下 🙏

相关推荐
Web极客码19 分钟前
深入了解WordPress网站访客意图
服务器·前端·wordpress
幺风1 小时前
Claude Code 源码分析 — Tool/MCP/Skill 可扩展工具系统
前端·javascript·ai编程
vjmap1 小时前
唯杰地图CAD图层加高性能特效扩展包发布
前端·gis
ZC跨境爬虫1 小时前
3D 地球卫星轨道可视化平台开发 Day7(AI异步加速+卫星系列精简+AI Agent自动评论)
前端·人工智能·3d·html·json
ID_180079054731 小时前
淘宝 API 上货 / 商品搬家 业务场景实现 + JSON 返回示例
前端·javascript·json
M ? A1 小时前
Vue 动态组件在 React 中,VuReact 会如何实现?
前端·javascript·vue.js·经验分享·react.js·面试·vureact
vipbic2 小时前
独立开发复盘:我用 Uni-app + Strapi v5 肝了一个“会上瘾”的打卡小程序
前端·微信小程序
IT_陈寒3 小时前
Vite的热更新突然失效,原来是因为这个配置
前端·人工智能·后端
ZC跨境爬虫3 小时前
3D 地球卫星轨道可视化平台开发 Day8(分步渲染200颗卫星+ 前端分页控制)
前端·python·3d·重构·html
竹林8183 小时前
RainbowKit快速集成多链钱包连接,我如何从“连不上”到“丝滑切换”
前端·javascript