用途
该技能用于指导在 Effect(TypeScript 函数式效果库)中管理可变状态。当用户询问 Effect Ref、可变状态、Ref.make、Ref.get、Ref.set、Ref.update、SubscriptionRef 等相关主题时启用。
主要能力
Effect 提供三种函数式可变状态原语,均为 fiber 安全,可在并发访问下正确工作:
- Ref:基础可变引用。
- SynchronizedRef:支持带效果(effectful)更新的 Ref。
- SubscriptionRef:支持变更通知的 Ref。
使用方式
Ref 基础用法
创建与操作 Ref:
import { Effect, Ref } from "effect"
const program = Effect.gen(function* () {
const counter = yield* Ref.make(0)
const current = yield* Ref.get(counter)
yield* Ref.set(counter, 10)
yield* Ref.update(counter, (n) => n + 1)
const old = yield* Ref.getAndSet(counter, 0)
const newValue = yield* Ref.updateAndGet(counter, (n) => n + 5)
const [oldVal, result] = yield* Ref.modify(counter, (n) => [n, n * 2])
})
原子操作
const atomicIncrement = Effect.gen(function* () {
const counter = yield* Ref.make(0)
yield* Effect.all([
Ref.update(counter, (n) => n + 1),
Ref.update(counter, (n) => n + 1),
Ref.update(counter, (n) => n + 1)
], { concurrency: "unbounded" })
return yield* Ref.get(counter)
})
在 Service 中使用 Ref
const CounterService = Effect.gen(function* () {
const ref = yield* Ref.make(0)
return {
increment: Ref.update(ref, (n) => n + 1),
decrement: Ref.update(ref, (n) => n - 1),
get: Ref.get(ref),
reset: Ref.set(ref, 0)
}
})
const CounterLive = Layer.effect(Counter, CounterService)
SynchronizedRef:带效果的更新
适用于更新过程需要运行效果的情况:
import { Effect, SynchronizedRef } from "effect"
const program = Effect.gen(function* () {
const ref = yield* SynchronizedRef.make({ count: 0, lastUpdated: Date.now() })
yield* SynchronizedRef.updateEffect(ref, (state) =>
Effect.gen(function* () {
yield* Effect.log("Updating state")
return { count: state.count + 1, lastUpdated: Date.now() }
})
)
const result = yield* SynchronizedRef.modifyEffect(ref, (state) =>
Effect.gen(function* () {
const newCount = state.count + 1
yield* sendMetric("counter", newCount)
return [newCount, { ...state, count: newCount }]
})
)
})
何时使用 SynchronizedRef:更新需要 API 调用、需要日志/指标、依赖外部状态或需要错误处理时。例如带异步刷新的缓存:
const cache = yield* SynchronizedRef.make<Data | null>(null)
const refreshCache = SynchronizedRef.updateEffect(cache, () =>
Effect.tryPromise(() => fetchLatestData())
)
SubscriptionRef:响应式状态
适用于需要通知订阅者的状态:
import { Effect, SubscriptionRef, Stream } from "effect"
const program = Effect.gen(function* () {
const ref = yield* SubscriptionRef.make(0)
const changes = yield* SubscriptionRef.changes(ref)
yield* Effect.fork(
Stream.runForEach(changes, (value) => Effect.log(`Value changed to: ${value}`))
)
yield* SubscriptionRef.set(ref, 1)
yield* SubscriptionRef.update(ref, (n) => n + 1)
yield* SubscriptionRef.set(ref, 10)
})
响应式模式示例,多个订阅者监听配置变更:
const configRef = yield* SubscriptionRef.make(initialConfig)
const subscriber1 = Effect.fork(
Stream.runForEach(SubscriptionRef.changes(configRef), (config) => updateService1(config))
)
const subscriber2 = Effect.fork(
Stream.runForEach(SubscriptionRef.changes(configRef), (config) => updateService2(config))
)
yield* SubscriptionRef.set(configRef, newConfig)
三者对比
| 特性 | Ref | SynchronizedRef | SubscriptionRef |
|---|---|---|---|
| 基础 get/set | ✅ | ✅ | ✅ |
| 原子更新 | ✅ | ✅ | ✅ |
| 带效果更新 | ❌ | ✅ | ❌ |
| 变更通知 | ❌ | ❌ | ✅ |
| 适用场景 | 简单状态 | 异步更新 | 响应式状态 |
常见模式
计数器 Service
class Counter extends Context.Tag("Counter")<
Counter,
{
readonly increment: Effect.Effect<number>
readonly decrement: Effect.Effect<number>
readonly get: Effect.Effect<number>
}
>() {}
const CounterLive = Layer.effect(
Counter,
Effect.gen(function* () {
const ref = yield* Ref.make(0)
return {
increment: Ref.updateAndGet(ref, (n) => n + 1),
decrement: Ref.updateAndGet(ref, (n) => n - 1),
get: Ref.get(ref)
}
})
)
状态机
type State = "idle" | "loading" | "success" | "error"
const stateMachine = Effect.gen(function* () {
const state = yield* Ref.make<State>("idle")
const transition = (from: State, to: State) =>
Ref.modify(state, (current) => current === from ? [true, to] : [false, current])
return {
state: Ref.get(state),
startLoading: transition("idle", "loading"),
succeed: transition("loading", "success"),
fail: transition("loading", "error"),
reset: Ref.set(state, "idle")
}
})
累加器
const accumulator = Effect.gen(function* () {
const items = yield* Ref.make<Array<Item>>([])
return {
add: (item: Item) => Ref.update(items, (arr) => [...arr, item]),
getAll: Ref.get(items),
clear: Ref.set(items, []),
count: Effect.map(Ref.get(items), (arr) => arr.length)
}
})
最佳实践
- 使用 Ref 处理简单状态:基础计数器、标志、累加器。
- 使用 SynchronizedRef 处理异步更新:当更新需要效果时。
- 使用 SubscriptionRef 处理响应式模式:当其他部分需要通知时。
- 保持状态最小化:不要存储派生数据。
- 优先不可变更新:返回新对象,不要直接变更。
适用场景
需要使用 Effect 管理并发安全状态、异步缓存刷新、响应式配置更新,或在 Service 中封装计数器、状态机、累加器等逻辑的 TypeScript 项目。
附加资源
关于状态管理的完整文档,可查阅 ${CLAUDE_PLUGIN_ROOT}/references/llms-full.txt,搜索 "Ref"(基础可变引用)、"SynchronizedRef"(带效果更新)、"SubscriptionRef"(响应式状态)等章节。
限制
资料未说明该技能的运行环境依赖、版本要求或收费信息。