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

@violetflux/kerros

v0.3.4

Published

Hook-native state sharing for React with automatic access tracking and focused selectors.

Downloads

1,987

Readme

Kerros 是一个在 React 组件间共享状态的轻量方案。

你怎么写 custom Hook,就可以怎么写 Store。只有当局部状态需要被多个组件使用时,再交给 createStore,用 Provider 决定共享范围;组件直接解构需要的数据,Kerros 默认自动追踪实际访问的属性。

[!TIP] 使用 Coding Agent 安装:复制下面这句话并粘贴给你的 Coding Agent,它会同时安装依赖和当前项目的 Skill:

使用当前项目的包管理器安装 @violetflux/kerros,然后运行 npx skills add violetflux/kerros --skill kerros --agent '*' -y,为当前项目中所有兼容的 Coding Agent 安装 Kerros Skill。

快速上手

创建 Store

任意 custom Hook 都可以变成 Kerros Store:

import { createStore } from '@violetflux/kerros'
import { useState } from 'react'

interface Task {
  id: string
  title: string
}

function useTaskModel() {
  const [tasks, setTasks] = useState<Task[]>([])

  const addTask = (task: Task) => {
    setTasks(v => [...v, task])
  }

  const finishTask = (taskId: string) => {
    setTasks(v => v.filter(task => task.id !== taskId))
  }

  return { tasks, addTask, finishTask }
}

export const [useTask, TaskProvider, getTask] = createStore(useTaskModel)

createStore 返回组件 Hook、对应的 Provider,以及在 React 外命令式读取已提交实例的 getter。

Store 仍然是普通 React Hook,可以继续使用 useStateuseReducer、Context、SDK Hook 或其他 custom Hook。

请把 initializer 写成 useTaskModel 这类同文件顶层命名 Hook。匿名 initializer 在运行时仍然可用,但 React Compiler 的 infer 模式不会自动把它识别并编译为 Hook。

挂载 Provider

只有 TaskProvider 的子节点可以调用 useTask

function App() {
  return (
    <TaskProvider>
      <Header />
      <TaskList />
    </TaskProvider>
  )
}

使用 Store

直接读取 Store。Kerros 会自动追踪组件渲染期间访问的属性:

function TaskList() {
  const { tasks, finishTask } = useTask()

  return (
    <ul>
      {tasks.map(task => (
        <li key={task.id}>
          {task.title}
          <button onClick={() => finishTask(task.id)}>完成</button>
        </li>
      ))}
    </ul>
  )
}

没有读取的字段发生变化时,TaskList 不会重渲染。自动追踪支持对象、数组和深层属性访问,不会对完整 Store 做深比较。

安装

| 包管理器 | 命令 | | --- | --- | | npm | npm install @violetflux/kerros | | pnpm | pnpm add @violetflux/kerros | | Yarn | yarn add @violetflux/kerros | | Bun | bun add @violetflux/kerros |

支持 React 17、React 18 和 React 19。

为什么要用 Kerros?

  • 几乎没有学习成本:直接复用已有的 React 知识,你怎么写 custom Hook,就可以怎么写 Store
  • 为灵活重构而设计:Store 和组件使用同一套 Hook API,可以近乎零成本地把组件局部状态转换成组件间共享状态
  • 同时支持局部状态和全局状态:Provider 决定 Store 的作用域,在灵活和简单之间取得平衡
  • 解决 Context 的重复渲染问题:Context 只传递稳定容器,组件观察到的值不变时不会重渲染
  • 优秀的 TypeScript 支持:Store 和 selector 类型自动推断,不需要重复声明

从状态管理到状态共享

Redux、Zustand、Recoil 这些状态管理库当然也能解决数据共享问题,但它们最核心的能力仍然是组织数据、操作数据和约束数据流,因此它们应该被称为“状态管理”工具。

Kerros 想解决的问题更小,也更直接。它不发明新的数据结构,不规定异步和数据流应该怎么写,只聚焦一个痛点:如何在多个 React 组件间共享一段 Hook 状态。

层层传递 valueonChange 会逐渐破坏组件边界;粗暴地把数据全部塞进一个全局 Store,也不会自动让应用获得更好的扩展性和可维护性。

直接用 React Context 共享变化频繁的状态也会带来重复渲染:Context value 每次变化,所有消费者都会更新。Kerros 保留 Provider 的作用域和多实例能力,但 Context 只传递稳定容器;自动追踪根据渲染期间的读取建立订阅,无关 Store 更新不会触发组件重渲染。

Kerros 简单、轻量、可靠。先把状态写成普通 Hook,需要共享时再交给 createStore;Provider 决定状态共享到哪里,自动追踪决定每个组件订阅什么。

三种订阅模式

不传 selector 是默认用法,也是多数场景的起点:

const { count, setCount } = useCounter()
  • useStore():自动追踪渲染期间读取的对象、数组和深层属性。
  • useStore(selector):用于高级派生值和经过测量的性能热点;Kerros 用 Object.is 浅比较 selector 返回对象的顶层字段。
  • createStore(model, { tracking: false })bindStore({ tracking: false }):关闭自动追踪,无 selector 读取改为完整 Store 顶层浅比较。

基础类型快照使用 Object.isMapSet、类实例及其他非普通对象按整体引用处理。Store 和 External Store 快照必须保持不可变:每次可观察变化都发布新引用。

React Element 和 Portal 会自动作为原子值处理。React 17、18、19 的标准 useRef()createRef() 容器可以直接返回。只有第三方对象不能接受 Proxy,或者必须保留严格身份时才使用 ref(value);原子值的内部原地修改不是响应式更新。

无 selector 的结果是当前组件的只读追踪快照,可以直接解构、保存在渲染局部变量中,或传给同步渲染的子组件继续读取。不要修改快照,也不要把它保存到 state、ref、模块变量或长期缓存后当作实时状态源;展开、rest 解构、枚举和序列化会形成宽泛订阅。响应式 Effect 应在渲染期间读取值并声明正确依赖;只有不参与渲染、需要执行时读取最新状态的命令式逻辑才使用 useInstance()。也不要把 Effect Event 暴露成公共 Store action。

多个实例

每个 TaskProvider 都拥有独立状态:

<TaskProvider>
  <h2>个人任务</h2>
  <TaskList />
</TaskProvider>

<TaskProvider>
  <h2>团队任务</h2>
  <TaskList />
</TaskProvider>

每个 TaskList 会自动读取离自己最近的 Provider。

Store 之间的依赖

一个 Store 可以直接调用另一个 Store。例如任务 Store 读取当前账户:

function useTaskModel() {
  const { user } = useAccount()
  const [tasks, setTasks] = useState<Task[]>([])

  const addTask = (title: string) => {
    if (!user)
      return

    setTasks(v => [...v, {
      id: crypto.randomUUID(),
      title,
      assigneeId: user.id,
    }])
  }

  return { tasks, addTask }
}

export const [useTask, TaskProvider] = createStore(useTaskModel)

按依赖顺序挂 Provider,并保持单向依赖:

<AccountProvider>
  <TaskProvider>
    <App />
  </TaskProvider>
</AccountProvider>

Provider props

Provider props 会传给 Store Hook:

interface CounterProps {
  initialCount: number
}

function useCounterModel({ initialCount }: CounterProps) {
  const [count, setCount] = useState(initialCount)
  return { count, setCount }
}

const [useCounter, CounterProvider] = createStore(useCounterModel)
<CounterProvider initialCount={42}>
  <Counter />
</CounterProvider>

API

createStore(默认用法)

function createStore<TStore, TProps = Record<never, never>>(
  useModel: (props: TProps) => TStore,
  options?: { tracking?: boolean },
): readonly [StoreHook<TStore>, StoreProvider<TProps>, StoreGetter<TStore>]
  • useModel 必须遵守 Hooks 规则
  • children 外的 Provider props 会传给 useModel
  • Provider 接受可选的 scope?: string | number | symbol,用于命令式查找
  • Store Hook 可不传参数使用自动追踪,也可传入返回对象的 selector
  • getter 读取最后挂载且已提交的 Provider,或 scope 精确匹配的最后一个实例;它不会订阅更新
  • 在对应 Provider 外调用会抛出明确错误
  • 支持 Strict Mode、服务端渲染和 Provider 多实例

ref(身份逃生口)

function ref<T extends object>(value: T): T

把对象标记为原子值并返回完全相同的身份。标准 React ref 不需要这个辅助函数。

高级用法:绑定已有 External Store

绝大多数应用只需要 createStore。只有当某个库或 SDK 已经在 React 外持有权威状态,并提供稳定的 getSnapshotsubscribe 函数时,才使用 bindStore

没有这个 API 时,集成层只能重复实现 Context 和细粒度订阅,或者把 External Store 快照复制进第二个 Store。bindStore 提供 Provider 作用域、无 selector 自动追踪和显式 selector,原 Store 仍是唯一状态所有者。

const [useStream, StreamBindingProvider] = bindStore<Stream>('Stream')

<StreamBindingProvider store={stream}>
  <App />
</StreamBindingProvider>

Provider 的 Context 只保存原 Store 实例,组件直接订阅它;Kerros 不复制快照,也不增加中间发布层。创建 Store 的组件继续负责生命周期和命令式访问。

一句话理解:bindStore 是 External Store 的 React 适配器,不是状态同步器。状态仍只存在于原 Store 中,React 在收到订阅通知后通过 getSnapshot 读取它。

如果状态来自 useStateuseReducer、SDK Hook 或其他 custom Hook,继续使用 createStore

React 17 使用官方 use-sync-external-store shim;React 18 和 19 可用时优先使用 React 原生实现。React Compiler 不是必需项。

ESLint 防护规则

建议安装轻量插件,检查当前文件内的 Kerros 约束:

npm install --save-dev @violetflux/eslint-plugin-kerros @typescript-eslint/parser
import kerros from '@violetflux/eslint-plugin-kerros'

export default [kerros.configs.recommended]

recommended 是插件唯一的预设,不启用 TypeScript projectService。它识别直接导入的 createStorebindStore、本地别名和 namespace 导入,并检查同一文件内生成的 Store 绑定与 Hook 调用。跨文件转导出、包装函数和从其他文件导入的 Store Hook 有意留在轻量边界之外。请参考真实 ESLint 压测

预设包含六条规则,覆盖工厂作用域、Model 与绑定命名、selector 参数名、返回完整 Store,以及对当前文件无 selector 快照的宽泛访问。插件优先保证内存有界和诊断稳定,不追踪跨文件类型身份。

维护者还需要分别为 @violetflux/kerros@violetflux/eslint-plugin-kerros 配置 npm Trusted Publisher。这是唯一的仓库外发布步骤;仓库内工作流会先检查并发布运行库,再发布插件。

文档

许可证

MIT