Overview
Build reactive state for .NET: update a value, and the computations that depend on it update too.
- Signals hold values you can read and write.
- Memos derive values from tracked reads.
- Effects run when a value they read changes.
- Bindings copy one fixed signal or memo into an external target.
A taste
open Ranvier
let graph = new Graph ()
let doubled =
graph.Run (fun () ->
let count = createSignal 1
let doubled = createMemo (fun _ -> count.Value * 2)
createEffect (fun () -> printfn "doubled = %d" doubled.Value)
count.Value <- 5
doubled)
doubled = 2
doubled = 10
What you get
Targets
net10.0, netstandard2.1 and Fable (JavaScript).
Guide
- Installation: preview packages, supported targets and Native AOT.
- Getting started: a short walkthrough of a reactive graph.
- Examples: complete F# and C# console and Avalonia applications for real workflows.
- Ranvier or Adaptive for a desktop app?: a blog walkthrough with a complete F# window and comparisons of state, bindings, collections, async work and lifetime.
- Graphs, Signals, Memos and Effects: the core primitives.
- Fixed-dependency bindings: copy one signal or memo into a target, with batching and owner disposal.
- Equality: graph defaults and typed comparers for individual nodes.
- Roots and owners, Cleanup, Untrack and Batch: lifetime and tracking controls.
- Editable values and Drafts: local edits over upstream state.
- Async and pending: in-flight values, async memos, boundaries, and threading.
- Debounce and throttle: control admission before downstream or async work starts.
- Streams: fold a stream's items into a node that restarts when its inputs change.
- Testing async state: deterministic tests that decide when each flight lands.
- Blazor Server: one graph per circuit, with
ThreadAffinity.Serialised. - Collections: projections, editable keyed sources, change readers, lookups and collection views.
- Aggregates: totals, counts and folds over collection rows.
- Forms: records of reactive fields and batched resets.
- Tracing: why a node ran or did not run, where it was created, and the graph as it stands.
- Signal maps: how to read the live graph maps beneath the examples, and how to write one.
- Troubleshooting: each exception message and common symptom, with its cause and fix.
- Migrating from Elmish: an MVU model read through selector memos, one view at a time.
- Queries and mutations: shared remote queries, page leases and atomic reconciliation of partial data.
- C#: C# factories, XAML bindings and reactive commands.
- Views and Server rendering: template components for the browser DOM, server HTML and hydration, in the alpha
Ranvier.Viewpackages.
Status
Implementation status and planned features
| Area | Status |
|---|---|
| Core graph (signal, memo, effect, owners, batching) | Implemented and tested. |
| Fixed-dependency bindings | bindSignal and bindMemo provide owned, untracked writes from one declared source; see Bindings. |
| Debounce and throttle | Implemented with eager capture, timed publication and injectable clocks; see Timing. |
| Per-node typed comparers | Implemented for signals, memos, split effects and boundaries; see Equality. |
| Editable keyed collections and value readers | Implemented, with direct row edits and bounded change cursors; see Direct edits and Reading changes. |
| Async and boundaries | Implemented. A pending .Value read throws NotReadyException; TryValue reads without throwing. |
| Per-node flight policies | Implemented: createAsyncWithPolicy and createOwningAsyncWithPolicy override the graph's policy for one async memo; see Async memos. |
Stream memos (createStream, createStreamFold) | Implemented and tested; see Streams. |
| Projections, lookups and selectors | Implemented, including memo-free factory rows, opt-in create-first passes and trimmed reconciliation; see Projections. |
| Fable/JavaScript | Implemented; package builds contain standalone Fable source projects. CI checks repository tests and packed consumers. See Fable (JavaScript) target. |
Collection combinators (Projection.filter, choose, map, mapWith, sortBy, groupBy) | Implemented and tested, including pending and error behaviour; see Collections. |
Editable values (createEditable, createDraft) and the MVU bridge (Mvu, in the Ranvier.Elmish package) | Implemented and tested; see Editable values and forms and Migrating from Elmish. |
| Shared remote queries and mutations | Implemented in Ranvier.Query, with acquired leases, retained refresh data and atomic reconciliation; see Queries and mutations. |
| Reusable lens and prism values for deep writes | Not implemented; they wait on a need for reusable focus paths over collections. |