コンテンツにスキップ

索引

SynStateはアプリケーションの状態を管理するためのシンプルで直感的なAPIを提供します:

イベント駆動パターンのための組み込みイベントエミッター:

複雑なシナリオに対応するため、SynStateはObservableベースのAPIを提供します:

  • source<T>(): 新しいObservableソースを作成(RxJSのsubjectとほぼ同等)。
  • just(value): 単一の静的な値を保持し即座に完了するObservableを作成。switchMap 内の同期フォールバックとして有用。
  • empty(): 値を持たず即座に完了しているObservableを作成(RxJS の EMPTY とほぼ同等)。switchMap で何も追わない分岐に有用。
  • fromPromise(promise): PromiseからObservableを作成。
  • fromAbortablePromise(factory): AbortSignal を受け取る Promise のファクトリから Observable を作成。Observable が complete すると(switchMap が切り替えたときなど)abort される。
  • fromSubscribable(): 任意のsubscribableオブジェクトからObservableを作成。
  • counter(ms): すぐに 0 を発行し、その後一定間隔で 1, 2, … を発行(RxJSのtimer(0, ms)とほぼ同等。{ emitInitial: false } を渡すとinterval(ms)とほぼ同等。{ times: n } を渡すとn回発行した直後に complete)。
  • timer(delay): 遅延後に発行。
  • map(fn): 値を変換。
  • mapTo(value): すべての値を定数にマッピング。
  • getKey(key): オブジェクトからプロパティ値を抽出(別名: pluck)。
  • attachIndex(): 各値にインデックスを付与(別名: withIndex)。
  • mergeMap(fn): Observableにマッピングしてすべてをマージ(並列実行)(別名: flatMap)。
  • switchMap(fn): Observableにマッピングして最新に切り替え(前のものをキャンセル)。
  • audit(ms): 指定した時間ウィンドウ後に最後の値を発行(RxJSのauditTimeとほぼ同等)。
  • debounce(ms): 発行をデバウンス(RxJSのdebounceTimeとほぼ同等)。
  • throttle(ms): 発行をスロットル(RxJSのthrottleTimeとほぼ同等)。
  • pairwise(): 前回と今回の値をペアとして発行。
  • scan(reducer, seed): 値を蓄積。
  • withBuffered(observable): Observableからの値をバッファリングし、親とともに発行(別名: withBufferedFrom)。
  • withCurrentValueFrom(observable): 別のObservableから現在の値をサンプリング(別名: withLatestFrom)。
  • withInitialValue(value): 未初期化のObservableに初期値を提供。
  • keepEqualParts(options?): 前の値と等しい部分を前の値のもので置き換え、全体が等しい値は流さない(構造共有)。自分で書き込む状態には createState の keepEqualParts オプションを優先。

スコープ(ライブラリ作成者向け)

Section titled “スコープ(ライブラリ作成者向け)”

ページの一部をマウント・破棄する UI 束縛のような、SynState の上に載るライブラリのための API。モジュールのトップレベルで定義したアプリの状態はどのスコープにも属さず、これを使う必要はない。

  • createScope(parent?, { after? }): スコープを作る。scope.run(body) の中で同期的に作られた Observable はそのスコープに属し、scope.dispose() は派生元の共有された Observable を complete せずにそれらを dispose する。そこで行った subscribe もそのスコープに属し、dispose() で購読が解除される。parent を渡すと親と一緒に dispose される。after を渡すと、そのスコープと子スコープの中で派生した Observable は、ソースから何段目であっても after より後に更新される。分岐をそのスコープにマウントする切り替えが、切り替えの元になる値を渡すと、次の値で外れる分岐を、分岐がその値を計算する前に破棄できる。
  • getCurrentScope(): run を実行中のスコープ(無ければ undefined)。スコープに入るのは同期的に作られたものだけなので、await の後の処理は同期部分で取っておいたスコープの run で包む。
  • onScopeDispose(cleanup): 現在のスコープが dispose されるときに cleanup を呼ぶ。
  • untracked(body): 現在のスコープ無しで body を呼び、その中で作られたものと購読を、囲むスコープより長く生かす。

dispose() は購読、子スコープ、onScopeDispose の関数、所有する Observable の順に、それぞれ新しいものから破棄する。そのため、スコープの中で行った購読は、onScopeDispose の関数が書いた値も、スコープやその子が dispose する Observable の complete も受け取らない。更新の伝搬と complete の通知は、どのスコープが値を書いたか、complete したかによらずスコープ無しで行われるので、それを受けて subscriber が行った購読や作った Observable は、subscriber 自身がスコープを run しない限りどのスコープにも属さない。dispose 済みのスコープで run すると warning を出し、その中で作られたものはどのスコープにも属さない。

  • isChildObservable(obs): ObservableがChild Observableかどうかを判定。
  • isManagerObservable(obs): ObservableがManager Observableかどうかを判定。
  • isRootObservable(obs): ObservableがRoot Observableかどうかを判定。

React / Preact Hooks (synstate-react-hooks / synstate-preact-hooks)

Section titled “React / Preact Hooks (synstate-react-hooks / synstate-preact-hooks)”

両パッケージは同一のAPI面を持ちます。React 18+にはsynstate-react-hooks、Preactにはsynstate-preact-hooksを使用してください。

  • useObservableValue(observable$): Observableを購読し、現在の値をコンポーネントの状態として返す。内部的にuseSyncExternalStoreを使用し、Observableが値を発行するとコンポーネントが再レンダリングされる。
  • useObservableValue(observable$, fallback): 上記と同じ。初期値を持たないObservableに対するフォールバック値を指定。
  • useObservableEffect(observable$, fn): コンポーネントがマウントされている間 fn を購読する(詳細)。
  • useValueAsObservable(value): コンポーネントのpropやstateの値をsynstateのObservableに変換。React/Preactの状態をObservableグラフに橋渡しする際に有用。Observable はコンポーネントのアンマウントで完了する。React では <Activity> が隠れてから再び表示されると別の Observable に置き換わるので、最初のものを持ち続けず、毎回のレンダーで受け取ったものを使う。

コアのcreateState / createReducer / createBooleanStateを再エクスポートしますが、タプルの最初の要素としてraw Observableの代わりにフック(useCurrentValue)を返します:

  • createState(initialValue): [useCurrentValue, setState, { state, updateState, resetState, getSnapshot, initialState }]を返す。
  • createReducer(reducer, initialState): [useCurrentValue, dispatch, { state, getSnapshot, initialState }]を返す。
  • createBooleanState(initialValue): [useCurrentValue, { state, setTrue, setFalse, toggle, setState, updateState, resetState, getSnapshot, initialState }]を返す。

synstateのObservableとPreact Signalsを橋渡しし、コンポーネントの再レンダリングなしにきめ細かいDOM更新を実現します。hooksアプローチとの比較はインタラクティブデモを参照してください。

  • toSignal(observable$): Observable(またはInitializedObservable)をPreactのReadonlySignalに変換。SignalはObservableと同期し続ける。JSXに直接埋め込み可能 — コンポーネント全体ではなく、影響を受けるテキストノードのみが更新される。
  • toSignal(observable$, fallback): 上記と同じ。初期値を持たないObservableに対するフォールバック値を指定。
  • fromSignal(signal): PreactのSignalをsynstateのInitializedSourceObservableに変換。[observable, dispose]を返す。ObservableはSignalの値をミラーリングし、synstateのオペレーターチェーン(map、debounce、switchMap等)を適用可能。

hooksラッパーと同じですが、フックの代わりに**ReadonlySignal**を返します:

  • createState(initialValue): [signal, setState, { state, updateState, resetState, getSnapshot, initialState }]を返す。
  • createReducer(reducer, initialState): [signal, dispatch, { state, getSnapshot, initialState }]を返す。
  • createBooleanState(initialValue): [signal, { state, setTrue, setFalse, toggle, setState, updateState, resetState, getSnapshot, initialState }]を返す。