diff --git a/ideas/dux.ts b/ideas/dux.ts index b2d4a69..a2af2ce 100644 --- a/ideas/dux.ts +++ b/ideas/dux.ts @@ -22,6 +22,7 @@ import type { KindReadonlyRecord } from "../record.ts"; import type { KindReadonlyArray } from "../array.ts"; import type { KindReadonlyMap } from "../map.ts"; import type { KindReadonlySet } from "../set.ts"; +import type { Optic, Rev, Tag } from "../optic.ts"; import * as D from "../datum.ts"; import * as DE from "../datum_either.ts"; @@ -465,8 +466,22 @@ export function onAction( * @since 2.1.2 */ export type Store = { - readonly state: Stream; + /** + * A function to dispatch an action to be reduced by the store. + */ readonly dispatch: (action: ActionType) => void; + /** + * A stream of state changes, emitting changes after every dispatched and + * reduced action. + */ + readonly state: Stream; + /** + * A syncronous function that returns the current state. + */ + readonly get: { + (): S; + (viewFn: (s: S) => A): A; + }; }; /** @@ -490,18 +505,22 @@ export function createStore( export function createStore( initial: State, reducer: Reducer, - effect: Effect = () => S.empty(), + effect: Effect = S.empty, env: Env = S.DefaultEnv as Env, ): Store { + let heldState = initial; + const [dispatch, action] = S.createAdapter(); const state = pipe( + // Start with initial state S.wrap(initial), + // Then continue with a new state with each reduced action S.combine(pipe( action, S.scan(reducer, initial), )), - S.distinct(), + S.tap((state) => heldState = state), S.hold, ); @@ -510,5 +529,11 @@ export function createStore( S.forEach(dispatch, () => {}, env), ); - return { state, dispatch }; + function get(): State; + function get(viewFn: (s: State) => A): A; + function get(viewFn?: (s: State) => A): State | A { + return typeof viewFn === "function" ? viewFn(heldState) : heldState; + } + + return { dispatch, state, get }; }