Skip to content

Getting started

Create a graph, store state in signals, derive values with memos, and use effects to connect that state to your application.

Starting a desktop app, or comparing this with FSharp.Data.Adaptive? Read Ranvier or Adaptive for a desktop app? for a complete window and practical workflows. Examples lists complete F# and C# applications to clone and run.

A first graph

open Ranvier

let graph = new Graph()

A signal holds a value let count = createSignal 1.

A memo derives a value let doubled = createMemo (fun _ -> count.Value * 2).

And an effect runs when what it read changes:

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)
Example code
let count = createSignal 1
let doubled = createMemo (fun _ -> count.Value * 2)

createEffect (fun () -> printfn $"doubled = %d{doubled.Value}")

controls [
    button "Set" (fun () -> count.Value <- 5)
    |> describe "The write refreshes doubled from 2 to 10."
    |> expect "The write refreshes doubled from 2 to 10." (fun () -> doubled.Peek = 10)
]

Make the graph active

The create* functions use the active graph. graph.Run activates it for the body and restores the previous graph afterward. For a longer scope, keep the handle returned by graph.Activate ():

open Ranvier

use graph = new Graph ()
use active = graph.Activate ()

let count = createSignal 1
let doubled = createMemo (fun _ -> count.Value * 2)
createEffect (fun () -> printfn "doubled = %d" doubled.Value)

count.Value <- 5

Disposing the graph releases its computations and runs their cleanups. In an application, keep the graph alive for as long as its state is needed.

Choose the next concept

  • Graphs: activation, explicit construction and graph configuration.
  • Signals: tracked reads, writes and equality.
  • Memos: lazy derived values, previous values and dynamic dependencies.
  • Effects: external work, scheduling and failures.
  • Roots and owners and Cleanup: lifetimes and resource release.
  • Untrack: read current values without subscribing.
  • Batch: combine writes into one effect flush.
  • Editable values and Drafts: local edits over upstream state.

Continue with Async and pending for loading and errors, or Collections for per-row reactivity and aggregates.

Edit this page