Ranvier 0.1.1-preview.1
dotnet add package Ranvier --version 0.1.1-preview.1
NuGet\Install-Package Ranvier -Version 0.1.1-preview.1
<PackageReference Include="Ranvier" Version="0.1.1-preview.1" />
<PackageVersion Include="Ranvier" Version="0.1.1-preview.1" />
<PackageReference Include="Ranvier" />
paket add Ranvier --version 0.1.1-preview.1
#r "nuget: Ranvier, 0.1.1-preview.1"
#:package Ranvier@0.1.1-preview.1
#addin nuget:?package=Ranvier&version=0.1.1-preview.1&prerelease
#tool nuget:?package=Ranvier&version=0.1.1-preview.1&prerelease
Ranvier
Fine-grained reactive computation for .NET and Fable.
Preview. Ranvier is pre-release. Its APIs may change before the first release.
Ranvier connects signals, memos and effects in a reactive graph. Signals hold writable state; memos derive values and recompute on demand after their inputs change; effects run side effects after changes. Async sources carry an explicit Pending state, and boundaries handle pending or failed reads.
open Ranvier
use graph = new Graph ()
graph.Run (fun () ->
let count = createSignal 1
let doubled = createMemo (fun _ -> count.Value * 2)
createEffect (fun () -> printfn "doubled = %d" doubled.Value)
count.Value <- 5)
C# projects reference Ranvier.CSharp, which adds delegate-based factories and extension methods.
Targets
net10.0 and netstandard2.1. Applications on .NET 8 and .NET 9 use the netstandard2.1 build.
Package builds from this source include F# sources for Fable's JavaScript target. The same core APIs support signals, memos, effects, bindings and collections on both targets; see the Fable guide.
Fixed-dependency bindings and ownership
bindSignal source target write and bindMemo source target write copy one source into an
external target in the flush. The writer receives the target and current value, runs untracked
and must not create reactive nodes. A pending or failed memo leaves the target unchanged;
an equal source value does not write again. Both factories return unit and attach to the current owner.
Use a memo before bindMemo to derive a target value, or an effect for work with dynamic dependencies.
Owners dispose children and cleanups together in reverse acquisition order. A cleanup registered after a child is created runs before that child is disposed, both on disposal and before a run's owned resources are replaced. See Bindings and Cleanup.
Keyed row factories
createProjectionWithOptions ProjectionOptions.CreateFirst keyOf factory source creates added
rows before retiring removed rows. If a new factory throws, the pass disposes its additions and
keeps the previously applied rows, items and keys until a source change retries the pass.
createProjectionOnce options keyOf factory source stores one factory result per key without a
row memo. It suits a view object whose factory creates its own bindings. Key readers are supported;
value readers, AsObservableCollection and projection view/aggregate operators are not. Use createProjectionWith
when those consumers need reactive row values. See
Projections.
Per-node equality
Ordinary factories use GraphOptions.Equality. To override a node's value cutoff, supply a
typed IEqualityComparer<T>:
let name = createSignalWithComparer System.StringComparer.OrdinalIgnoreCase "Ada"
let label = createMemoWithComparer System.StringComparer.OrdinalIgnoreCase (fun _ -> name.Value.Trim())
The override applies to that node. Other nodes continue using the graph policy. A signal keeps its current value when the comparer treats a write as equal. A memo caches its computed result but suppresses downstream work when it compares equal. Pending, failed, waiting and caught-error state changes still propagate.
The opt-in factories are createSignalWithComparer, createMemoWithComparer,
createOwningMemoWithComparer, createEffectOnWithComparer, createSuspenseWithComparer,
createErrorBoundaryWithComparer and createBoundaryWithComparer. Their ownership, purity and
previous-value rules match the ordinary factories. Null comparers are rejected at construction.
A comparer exception leaves a signal unchanged and reaches its writer; on a computed node it
fails the node using its existing error handling. A boundary's recovery function handles body
errors, so a comparer error fails the boundary directly.
Comparers are selected once at construction. Async sources and async memos retain their completion/state notifications, and collection APIs retain their graph-policy cutoffs.
The C# facade adds comparer overloads, for example Reactive.Signal("Ada", StringComparer.OrdinalIgnoreCase)
and Reactive.Memo(() => name.Value.Trim(), StringComparer.OrdinalIgnoreCase).
Editable collections and change readers
let items = createKeyedCollection (fun (id, _) -> id)
items.Edit(fun edit ->
edit.AddOrUpdate(1, "write")
edit.AddOrUpdate(2, "test"))
let titles = items.Rows |> Projection.map snd
use reader = titles.NewValueReader ()
reader.Read () |> ignore // initial reset
items.AddOrUpdate(2, "retest")
let delta = reader.Read () // Changed for key 2
Reactive.KeyedCollection<T, K>(keyOf) is the C# factory. Rows supports the existing
map/filter/sort/group/aggregate operators. Updating a live key writes its value directly;
it preserves the key array and avoids scanning an input collection. New keys append.
Removing and re-adding a key creates a new row, reported as Replaced to a reader that saw
the old row. Removal searches insertion order in O(N); membership passes copy key order.
Edit batches synchronous writes and retains applied edits if its callback throws.
NewKeyReader() reports membership and order. NewValueReader() also reports Changed
for unequal settled row values under the graph policy. Each reader has an independent
bounded cursor; the first read and overflow return a reset. Deltas are coalesced refresh
hints containing keys, rather than value snapshots or a history of every intermediate write.
Read current values through the projection and handle pending/error states there.
Value readers share observation and accepted values while any value reader lives. Initial
observation evaluates every visible row; later value-only pulls evaluate suspect rows.
Pending or failed rows retain their last settled value, and status changes alone do not
produce Changed. Dispose readers to release observation. The .NET observable collection
adapter uses this cache to update changed rows without polling every row.
Map membership consumes upstream key deltas. Filters, sorts, grouping and some aggregate membership paths still scan keys; this is a foundation for incremental collections, with explicit costs for membership and order.
Tracing
Ranvier.Traced is the same assembly, namespaces and version built with the per-graph event log and its queries.
Reference it in place of Ranvier for development builds; see
Tracing.
Links
| Product | Versions Compatible and additional computed target framework versions. |
|---|---|
| .NET | net5.0 was computed. net5.0-windows was computed. net6.0 was computed. net6.0-android was computed. net6.0-ios was computed. net6.0-maccatalyst was computed. net6.0-macos was computed. net6.0-tvos was computed. net6.0-windows was computed. net7.0 was computed. net7.0-android was computed. net7.0-ios was computed. net7.0-maccatalyst was computed. net7.0-macos was computed. net7.0-tvos was computed. net7.0-windows was computed. net8.0 was computed. net8.0-android was computed. net8.0-browser was computed. net8.0-ios was computed. net8.0-maccatalyst was computed. net8.0-macos was computed. net8.0-tvos was computed. net8.0-windows was computed. net9.0 was computed. net9.0-android was computed. net9.0-browser was computed. net9.0-ios was computed. net9.0-maccatalyst was computed. net9.0-macos was computed. net9.0-tvos was computed. net9.0-windows was computed. net10.0 is compatible. net10.0-android was computed. net10.0-browser was computed. net10.0-ios was computed. net10.0-maccatalyst was computed. net10.0-macos was computed. net10.0-tvos was computed. net10.0-windows was computed. |
| .NET Core | netcoreapp3.0 was computed. netcoreapp3.1 was computed. |
| .NET Standard | netstandard2.1 is compatible. |
| MonoAndroid | monoandroid was computed. |
| MonoMac | monomac was computed. |
| MonoTouch | monotouch was computed. |
| Tizen | tizen60 was computed. |
| Xamarin.iOS | xamarinios was computed. |
| Xamarin.Mac | xamarinmac was computed. |
| Xamarin.TVOS | xamarintvos was computed. |
| Xamarin.WatchOS | xamarinwatchos was computed. |
-
.NETStandard 2.1
- Fable.Core (>= 5.3.0)
- FSharp.Core (>= 8.0.100)
-
net10.0
- Fable.Core (>= 5.3.0)
- FSharp.Core (>= 8.0.100)
NuGet packages (6)
Showing the top 5 NuGet packages that depend on Ranvier:
| Package | Downloads |
|---|---|
|
Ranvier.View
Template components for Ranvier: typed templates, view sugar, keyed lists, arms and boundaries, with server HTML rendering on .NET and under Fable. |
|
|
Ranvier.Elmish
An Elmish-style model-view-update bridge for Ranvier: a model held in a signal, updated by dispatched messages and read through selector memos. |
|
|
Fable.Ranvier.Anime
Typed anime.js 4.5 bindings for Fable, with Ranvier integration: parameters as constructors with named optional arguments, and per-feature imports. |
|
|
Ranvier.CSharp
C# entry points for Ranvier: delegate-based factories and extension methods. |
|
|
Ranvier.Query
Typed reactive queries and mutation reconciliation for partially loaded application data. |
GitHub repositories
This package is not used by any popular GitHub repositories.
| Version | Downloads | Last Updated |
|---|---|---|
| 0.1.1-preview.1 | 1,416 | 10/28/2026 |
| 0.1.0-preview.7 | 168 | 10/26/2026 |
| 0.1.0-preview.6 | 81 | 10/21/2026 |
| 0.1.0-preview.5 | 89 | 10/4/2026 |
| 0.1.0-preview.4 | 78 | 10/3/2026 |
| 0.1.0-preview.3 | 72 | 9/30/2026 |
| 0.1.0-preview.2 | 70 | 9/30/2026 |
| 0.1.0-preview.1 | 70 | 9/29/2026 |
Preview release. The API may change before 1.0.