npm package discovery and stats viewer.

Discover Tips

  • General search

    [free text search, go nuts!]

  • Package details

    pkg:[package-name]

  • User packages

    @[username]

Sponsor

Optimize Toolset

I’ve always been into building performant and accessible sites, but lately I’ve been taking it extremely seriously. So much so that I’ve been building a tool to help me optimize and monitor the sites that I build to make sure that I’m making an attempt to offer the best experience to those who visit them. If you’re into performant, accessible and SEO friendly sites, you might like it too! You can check it out at Optimize Toolset.

About

Hi, 👋, I’m Ryan Hefner  and I built this site for me, and you! The goal of this site was to provide an easy way for me to check the stats on my npm packages, both for prioritizing issues and updates, and to give me a little kick in the pants to keep up on stuff.

As I was building it, I realized that I was actually using the tool to build the tool, and figured I might as well put this out there and hopefully others will find it to be a fast and useful way to search and browse npm packages as I have.

If you’re interested in other things I’m working on, follow me on Twitter or check out the open source projects I’ve been publishing on GitHub.

I am also working on a Twitter bot for this site to tweet the most popular, newest, random packages from npm. Please follow that account now and it will start sending out packages soon–ish.

Open Software & Tools

This site wouldn’t be possible without the immense generosity and tireless efforts from the people who make contributions to the world and share their work via open source initiatives. Thank you 🙏

© 2026 – Pkg Stats / Ryan Hefner

@arronqzy/rx-store

v1.0.8

Published

RxJS-based state store for Abuilder

Readme

@arronqzy/rx-store

一个专为低代码/画布编辑器打造的极简、高性能、工业级状态管理库
基于 Immer + RxJS,天生支持:

  • 100% Immutable(写法却像 mutable)
  • 类似 Figma 的精准路径订阅(只重渲染改动的节点)
  • 完整的 Undo/Redo + Batch 操作(拖拽只记一次)
  • 插件系统(内置 + 第三方任意扩展)
  • 体积仅 ~15kB,TypeScript 体验完美

灵感来源:tldraw v2、Figma、Excalidraw、Linear、Retool 等新一代编辑器的核心状态层实现。

安装

# yarn / pnpm / npm 任意
yarn add @arronqzy/rx-store rxjs immer

快速开始

import { store } from '@arronqzy/rx-store';

// 1. 普通更新(写法跟 mutable 完全一样)
store.update(draft => {
  draft.root.children.push({
    id: 'text-1',
    type: 'text',
    props: { text: 'Hello World', x: 100, y: 100 }
  });
});

// 2. 拖拽防抖(只记一次历史)
store.startBatch('drag-node-123');
store.update(draft => {
  draft.root.children[0].props.x += 10;
});
store.endBatch();

// 3. Undo / Redo(Ctrl+Z / Ctrl+Y 直接可用)
store.undo();
store.redo();

核心 API

store.update(updater, options?)

store.update(draft => {
  // draft 就是普通对象,随便改!
  draft.selectedIds = ['node-1'];
}, {
  meta: { type: 'select' },
  skipHistory: false   // 可选:这次操作不进历史(比如光标移动)
});

store.selectPath(path)

精准订阅某一条路径的变化,只在真正改变时触发,完美适配 React/Vue 局部渲染。

store.selectPath<number>('root.children[2].props.x')
  .subscribe(x => {
    console.log('X 坐标变了:', x);
  });

// 支持嵌套数组写法
store.selectPath('root.children[0].props.style.fontSize')

Undo / Redo

store.undo();
store.redo();

// 响应式按钮状态
store.canUndo$.subscribe(can => btnUndo.disabled = !can);
store.canRedo$.subscribe(can => btnRedo.disabled = !can);

Batch 操作(拖拽、框选移动必备)

store.startBatch('move-multiple-nodes');
// ... 连续多次 update
store.endBatch();   // 整个过程只记一次历史

插件系统

import { store } from '@arronqzy/rx-store';

const autoSavePlugin = {
  name: 'auto-save',
  init(store) {
    store.select().subscribe(state => {
      localStorage.setItem('editor-state', JSON.stringify(state));
    });
  }
};

store.registerPlugin(autoSavePlugin);

插件可用的钩子:

  • init(store)
  • onBeforeUpdate(old, new)
  • shouldSkipHistory(old, new) → 返回 true 跳过本次历史记录
  • onUpdate(old, new)

完整示例:React Hook

import { store } from '@arronqzy/rx-store';
import { useEffect, useState } from 'react';

function useNode(id: string) {
  const [node, setNode] = useState(() =>
    store.getState().root.children.find(n => n.id === id)
  );

  useEffect(() => {
    const sub = store
      .selectPath(`root.children[${id}]`)  // 也可以写死索引或用 find
      .subscribe(setNode);
    return () => sub.unsubscribe();
  }, [id]);

  return node;
}

为什么选择这个方案(2025 最佳实践)

| 方案 | 体积 | TS 支持 | 性能 | 社区趋势 | |---------------------|--------|---------|----------|----------| | immutable.js | 150kB+ | 差 | 慢 30-200% | 已无人维护 | | zustand + immer | ~20kB | 好 | 快 | 流行 | | 本库 (Immer + RxJS) | ~15kB | 完美 | 最快 | 新一代编辑器标配 |

许可证

MIT © arronqzy