重要前提
安装AI Skills的关键前提是:必须科学上网,且开启TUN模式,这一点至关重要,直接决定安装能否顺利完成,在此郑重提醒三遍:科学上网,科学上网,科学上网。查看完整安装教程 →
tanstack-store by tanstack-skills/tanstack-skills
npx skills add https://github.com/tanstack-skills/tanstack-skills --skill tanstack-storeTanStack Store 是一个轻量级的响应式存储库(类似于 signals),为 TanStack 库的内部提供支持。它提供 Store 用于状态管理,Derived 用于计算值,Effect 用于副作用,以及 batch 用于原子更新。框架适配器提供了响应式钩子。
核心: @tanstack/store React: @tanstack/react-store
npm install @tanstack/store @tanstack/react-store
import { Store } from '@tanstack/store'
const countStore = new Store(0)
const userStore = new Store<{ name: string; email: string }>({
name: 'Alice',
email: 'alice@example.com',
})
广告位招租
在这里展示您的产品或服务
触达数万 AI 开发者,精准高效
// 函数式更新器(不可变更新)
countStore.setState((prev) => prev + 1)
userStore.setState((prev) => ({ ...prev, name: 'Bob' }))
const unsub = countStore.subscribe(() => {
console.log('Count:', countStore.state)
})
// 清理
unsub()
const store = new Store(initialState, {
// 自定义更新函数
updateFn: (prevValue) => (updater) => {
return updater(prevValue) // 自定义逻辑
},
// 订阅时的回调
onSubscribe: (listener, store) => {
console.log('新订阅者')
return () => console.log('已取消订阅')
},
// 每次更新时的回调
onUpdate: () => {
console.log('状态已更新:', store.state)
},
})
store.state // 当前状态
store.prevState // 前一个状态
store.listeners // 监听器回调的集合
import { Store, Derived } from '@tanstack/store'
const count = new Store(5)
const multiplier = new Store(2)
const doubled = new Derived({
deps: [count, multiplier],
fn: ({ currDepVals }) => currDepVals[0] * currDepVals[1],
})
// 必须挂载以激活
const unmount = doubled.mount()
console.log(doubled.state) // 10
count.setState(() => 10)
console.log(doubled.state) // 20
// 清理
unmount()
const accumulated = new Derived({
deps: [count],
fn: ({ prevVal, currDepVals }) => {
return currDepVals[0] + (prevVal ?? 0)
},
})
const filtered = new Derived({
deps: [dataStore, filterStore],
fn: ({ currDepVals }) => currDepVals[0].filter(matchesFilter(currDepVals[1])),
})
const sorted = new Derived({
deps: [filtered, sortStore],
fn: ({ currDepVals }) => [...currDepVals[0]].sort(comparator(currDepVals[1])),
})
const paginated = new Derived({
deps: [sorted, pageStore],
fn: ({ currDepVals }) => currDepVals[0].slice(
currDepVals[1].offset,
currDepVals[1].offset + currDepVals[1].limit,
),
})
import { Store, Effect } from '@tanstack/store'
const count = new Store(0)
const logger = new Effect({
deps: [count],
fn: () => {
console.log('Count changed:', count.state)
// 可选择返回清理函数
return () => console.log('清理中')
},
eager: false, // true = 在挂载时立即运行
})
const unmount = logger.mount()
count.setState(() => 1) // 日志: "Count changed: 1"
unmount()
const timerEffect = new Effect({
deps: [intervalStore],
fn: () => {
const id = setInterval(() => { /* ... */ }, intervalStore.state)
return () => clearInterval(id) // 在下一次运行或卸载时清理
},
})
将多个更新分组为一个通知:
import { batch } from '@tanstack/store'
// 订阅者只会在最终状态时触发一次
batch(() => {
countStore.setState(() => 1)
nameStore.setState(() => 'Alice')
settingsStore.setState((prev) => ({ ...prev, theme: 'dark' }))
})
import { useStore } from '@tanstack/react-store'
// 订阅完整状态
function Counter() {
const count = useStore(countStore)
return <button onClick={() => countStore.setState((c) => c + 1)}>{count}</button>
}
// 使用选择器订阅(性能优化)
function UserName() {
const name = useStore(userStore, (state) => state.name)
return <span>{name}</span>
}
// 订阅 Derived
function DoubledDisplay() {
const value = useStore(doubledDerived)
return <span>{value}</span>
}
防止选择器返回结构上相等的对象时重新渲染:
import { useStore } from '@tanstack/react-store'
import { shallow } from '@tanstack/react-store'
function TodoList() {
// 不使用 shallow:任何状态变更(新的对象引用)都会导致重新渲染
// 使用 shallow:仅当 items 实际发生变化时才重新渲染
const items = useStore(todosStore, (state) => state.items, shallow)
return <ul>{items.map(/* ... */)}</ul>
}
function MyComponent() {
useEffect(() => {
const unmountDerived = myDerived.mount()
const unmountEffect = myEffect.mount()
return () => {
unmountDerived()
unmountEffect()
}
}, [])
const value = useStore(myDerived)
return <span>{value}</span>
}
// stores/counter.ts
import { Store, Derived } from '@tanstack/store'
export const counterStore = new Store(0)
export const doubledCount = new Derived({
deps: [counterStore],
fn: ({ currDepVals }) => currDepVals[0] * 2,
})
// 将操作定义为普通函数
export function increment() {
counterStore.setState((c) => c + 1)
}
export function reset() {
counterStore.setState(() => 0)
}
| 框架 | 包 | 钩子/组合式函数 |
|---|---|---|
| React | @tanstack/react-store | useStore(store, selector?, equalityFn?) |
| Vue | @tanstack/vue-store | useStore(store, selector?) (返回 computed ref) |
| Solid | @tanstack/solid-store | useStore(store, selector?) (返回 signal) |
| Angular | @tanstack/angular-store | injectStore(store, selector?) (返回 signal) |
| Svelte | @tanstack/svelte-store | useStore(store, selector?) (返回 $state) |
useStore 中使用选择器以防止不必要的重新渲染shallowmount() 在 Derived 和 Effect 实例上setStatebatch 处理多个相关更新fn 中返回清理函数用于定时器/监听器mount() Derived/Effect(它们不会被激活)store.state 而不是使用 setStateshallowuseStore 时不带选择器(订阅所有内容)eager: true每周安装量
65
代码仓库
GitHub 星标数
5
首次出现
2026年2月21日
安全审计
已安装于
codex62
opencode61
gemini-cli60
cursor60
kimi-cli59
amp59
TanStack Store is a lightweight reactive store (signals-like) that powers the internals of TanStack libraries. It provides Store for state, Derived for computed values, Effect for side effects, and batch for atomic updates. Framework adapters provide reactive hooks.
Core: @tanstack/store React: @tanstack/react-store
npm install @tanstack/store @tanstack/react-store
import { Store } from '@tanstack/store'
const countStore = new Store(0)
const userStore = new Store<{ name: string; email: string }>({
name: 'Alice',
email: 'alice@example.com',
})
// Function updater (immutable update)
countStore.setState((prev) => prev + 1)
userStore.setState((prev) => ({ ...prev, name: 'Bob' }))
const unsub = countStore.subscribe(() => {
console.log('Count:', countStore.state)
})
// Cleanup
unsub()
const store = new Store(initialState, {
// Custom update function
updateFn: (prevValue) => (updater) => {
return updater(prevValue) // custom logic
},
// Callback on subscribe
onSubscribe: (listener, store) => {
console.log('New subscriber')
return () => console.log('Unsubscribed')
},
// Callback on every update
onUpdate: () => {
console.log('State updated:', store.state)
},
})
store.state // Current state
store.prevState // Previous state
store.listeners // Set of listener callbacks
import { Store, Derived } from '@tanstack/store'
const count = new Store(5)
const multiplier = new Store(2)
const doubled = new Derived({
deps: [count, multiplier],
fn: ({ currDepVals }) => currDepVals[0] * currDepVals[1],
})
// MUST mount to activate
const unmount = doubled.mount()
console.log(doubled.state) // 10
count.setState(() => 10)
console.log(doubled.state) // 20
// Cleanup
unmount()
const accumulated = new Derived({
deps: [count],
fn: ({ prevVal, currDepVals }) => {
return currDepVals[0] + (prevVal ?? 0)
},
})
const filtered = new Derived({
deps: [dataStore, filterStore],
fn: ({ currDepVals }) => currDepVals[0].filter(matchesFilter(currDepVals[1])),
})
const sorted = new Derived({
deps: [filtered, sortStore],
fn: ({ currDepVals }) => [...currDepVals[0]].sort(comparator(currDepVals[1])),
})
const paginated = new Derived({
deps: [sorted, pageStore],
fn: ({ currDepVals }) => currDepVals[0].slice(
currDepVals[1].offset,
currDepVals[1].offset + currDepVals[1].limit,
),
})
import { Store, Effect } from '@tanstack/store'
const count = new Store(0)
const logger = new Effect({
deps: [count],
fn: () => {
console.log('Count changed:', count.state)
// Optionally return cleanup function
return () => console.log('Cleaning up')
},
eager: false, // true = run immediately on mount
})
const unmount = logger.mount()
count.setState(() => 1) // logs: "Count changed: 1"
unmount()
const timerEffect = new Effect({
deps: [intervalStore],
fn: () => {
const id = setInterval(() => { /* ... */ }, intervalStore.state)
return () => clearInterval(id) // cleanup on next run or unmount
},
})
Group multiple updates into one notification:
import { batch } from '@tanstack/store'
// Subscribers fire only once with final state
batch(() => {
countStore.setState(() => 1)
nameStore.setState(() => 'Alice')
settingsStore.setState((prev) => ({ ...prev, theme: 'dark' }))
})
import { useStore } from '@tanstack/react-store'
// Subscribe to full state
function Counter() {
const count = useStore(countStore)
return <button onClick={() => countStore.setState((c) => c + 1)}>{count}</button>
}
// Subscribe with selector (performance optimization)
function UserName() {
const name = useStore(userStore, (state) => state.name)
return <span>{name}</span>
}
// Subscribe to Derived
function DoubledDisplay() {
const value = useStore(doubledDerived)
return <span>{value}</span>
}
Prevents re-renders when selector returns structurally-equal objects:
import { useStore } from '@tanstack/react-store'
import { shallow } from '@tanstack/react-store'
function TodoList() {
// Without shallow: re-renders on ANY state change (new object ref)
// With shallow: only re-renders when items actually change
const items = useStore(todosStore, (state) => state.items, shallow)
return <ul>{items.map(/* ... */)}</ul>
}
function MyComponent() {
useEffect(() => {
const unmountDerived = myDerived.mount()
const unmountEffect = myEffect.mount()
return () => {
unmountDerived()
unmountEffect()
}
}, [])
const value = useStore(myDerived)
return <span>{value}</span>
}
// stores/counter.ts
import { Store, Derived } from '@tanstack/store'
export const counterStore = new Store(0)
export const doubledCount = new Derived({
deps: [counterStore],
fn: ({ currDepVals }) => currDepVals[0] * 2,
})
// Actions as plain functions
export function increment() {
counterStore.setState((c) => c + 1)
}
export function reset() {
counterStore.setState(() => 0)
}
| Framework | Package | Hook/Composable |
|---|---|---|
| React | @tanstack/react-store | useStore(store, selector?, equalityFn?) |
| Vue | @tanstack/vue-store | useStore(store, selector?) (returns computed ref) |
| Solid | @tanstack/solid-store | useStore(store, selector?) (returns signal) |
| Angular |
useStore to prevent unnecessary re-rendersshallow when selectors return objects/arraysmount() on Derived and Effect instancessetStatebatch for multiple related updatesfn for timers/listenersmount() Derived/Effect (they won't activate)store.state directly instead of using setStateshallowuseStore without a selector (subscribes to everything)eager: true when Effect should run immediatelyWeekly Installs
65
Repository
GitHub Stars
5
First Seen
Feb 21, 2026
Security Audits
Gen Agent Trust HubPassSocketPassSnykPass
Installed on
codex62
opencode61
gemini-cli60
cursor60
kimi-cli59
amp59
Vercel React 最佳实践指南 | Next.js 性能优化与代码规范
10,600 周安装
DigitalOcean托管数据库完全指南:PostgreSQL、MySQL、Redis、MongoDB、Kafka等云数据库管理
101 周安装
Web安全漏洞大全:100个关键漏洞详解与修复指南 | 渗透测试必备
100 周安装
文章插图生成器 - AI智能分析文章内容,自动生成风格一致的信息图、流程图等插图
105 周安装
Weights & Biases (W&B) 使用指南:机器学习实验追踪与 MLOps 平台
63 周安装
AI 端到端测试工具 - 支持 8 大平台,零代码实现自动化测试
98 周安装
Confluence 专家指南:空间管理、文档架构、模板与协作知识库搭建
98 周安装
@tanstack/angular-store |
injectStore(store, selector?) (returns signal) |
| Svelte | @tanstack/svelte-store | useStore(store, selector?) (returns $state) |