diff --git a/packages/docs/docs/state-management.md b/packages/docs/docs/state-management.md index cd62f75..bcb0c49 100644 --- a/packages/docs/docs/state-management.md +++ b/packages/docs/docs/state-management.md @@ -18,6 +18,55 @@ scopes. The usual pattern is: core data model and transformation APIs belong to `effect-lens`, so check the `effect-lens` documentation for the full Lens/Subscribable API. +## Where To Store State + +State can live pretty much anywhere: in a service, in a layer, in a component +scope, or in plain React state. Pick the owner based on who needs the state. + +If state is shared by multiple components or belongs to application logic, store +it in an Effect service: + +```tsx +import { Effect, SubscriptionRef } from "effect" +import { Component, Lens, Subscribable } from "effect-fc" + +class CounterState extends Effect.Service()("CounterState", { + effect: Effect.gen(function* () { + const count = Lens.fromSubscriptionRef(yield* SubscriptionRef.make(0)) + + return { count } as const + }), +}) {} + +const CounterValueView = Component.make("CounterValue")(function* () { + const state = yield* CounterState + const [count] = yield* Subscribable.useAll([state.count]) + + return

Count: {count}

+}) +``` + +If state belongs to a single Effect-FC component instance but still benefits +from Lens/Subscribable APIs, create it with `Component.useOnMount`: + +```tsx +import { Effect, SubscriptionRef } from "effect" +import { Component, Lens, Subscribable } from "effect-fc" + +const LocalCounterView = Component.make("LocalCounter")(function* () { + const countLens = yield* Component.useOnMount(() => + Effect.map(SubscriptionRef.make(0), Lens.fromSubscriptionRef), + ) + const [count] = yield* Subscribable.useAll([countLens]) + + return

Count: {count}

+}) +``` + +For simple UI state that is not shared and does not need Effect integration, +prefer regular React state. A local "show details" toggle is usually better as +`React.useState(false)` than as a Lens. + ## Subscribables A `Subscribable` is reactive state with a current value and a stream of @@ -43,9 +92,12 @@ class CounterState extends Effect.Service()("CounterState", { const CounterReadOnlyView = Component.make("CounterReadOnly")( function* () { const state = yield* CounterState - const [doubled] = yield* Subscribable.useAll([state.doubled]) + const [count, doubled] = yield* Subscribable.useAll([ + state.count, + state.doubled, + ]) - return

Doubled: {doubled}

+ return

Count: {count}, doubled: {doubled}

}, ) ```