Guide / Reinhardt 0.3.15

Change one variable: which part of the screen moves?

In this guide

Two displays share a number called left. The first can switch between left and right; the second always shows left. When we switch the first display to right, a later write to left updates only the second display. The first still reads the current left value when we switch back.

The complete browser example uses Reinhardt Pages 0.3.15 and its supplied lockfile. It checks the displayed text, effect execution counts, and the dependency graph after seven states. Reinhardt Press is the project's own developer outreach publication.

Reads determine the active edges

The selected display is driven by this excerpt from the sample. Signal handles, the output text node, and the counter are cloned into the closure; the complete source contains the mounting and lifetime management.

Effect::new(move || {
    let value = if show_left.get() {
        left.get()
    } else {
        right.get()
    };
    runs.set(runs.get() + 1);
    output.set_data(&value.to_string());
})

get() returns the value and records a dependency when called under the active observer. If show_left is true, that execution reads show_left and left. It does not execute right.get(), even though the expression exists in the source. The graph therefore has edges from the switch and left to the selected effect. The other effect independently reads left.

The pinned Signal::get implementation records the read through the runtime. Before each effect execution, Effect::execute_effect clears its old dependencies and installs the observer for the new execution. The graph follows the latest executed reads.

Seven states in a real browser

These are observed results from the supplied browser regression. Execution counts include the initial effect run. Every setter explicitly flushes pending updates, so the test can inspect each write separately.

ActionSelected textLeft-only textSelected runsLeft-only runsSelected dependencies
Initial101011show_left, left
right = 101101011show_left, left
left = 11111122show_left, left
show_left = false1011132show_left, right
left = 121011233show_left, right
right = 1021021243show_left, right
show_left = true121253show_left, left

The first write to right wakes neither effect. The write to left wakes both. Switching branches reruns only the selected effect and replaces its left dependency with right. Now left = 12 leaves that effect at three executions while the left-only display changes.

Switching back produces 12: an ignored notification does not freeze the stored value. The new execution reads the current value and reestablishes the left edge. The regression also checks that the original selected text node remains attached, and that dropping the demo removes both effects from the runtime. It compares against independently specified expected states, rather than comparing two implementations that could share the same mistake.

Which API is doing the tracking?

This example deliberately uses low-level Effect::new, explicitly mounted browser text nodes, and Text::set_data. It does not test page! generated bindings, hydration, or component remount behavior. A passing text-node test cannot establish all of those broader guarantees.

The similarly named use_effect(callback, deps) uses an explicit dependency tuple. Its callback runs without the automatic observer used here; the listed dependencies govern subscriptions. See the pinned Pages hook documentation. get_untracked() also reads without adding a dependency. Identify the API and actual reads before using this graph to explain an unexpected update.

The sample exposes dependency names through debug_dependencies, a hidden diagnostic method in the pinned release. It is useful for this experiment, but is not presented as a stable application integration API.

Run it and change one read

Extract the ZIP and enter its signal-dependencies directory. Install Rust 1.96 or newer, wasm-pack, Chrome/Chromium, and a matching ChromeDriver on PATH. The README explains how to select a nondefault browser binary.

rustup target add wasm32-unknown-unknown
wasm-pack test --headless --chrome -- --nocapture

The test prints SIGNAL_EVIDENCE= followed by JSON after its assertions pass. To use the same library as an interactive app:

wasm-pack build --target web --dev -- --locked
python3 -m http.server 8091 --bind 127.0.0.1

Open http://127.0.0.1:8091/. The first build downloads and compiles dependencies. This experiment needs no database, Docker, npm, or Reinhardt server. The video is an edited explanation, not an installation stopwatch.

Try a third source or a nested condition. Predict the dependencies after each branch, then assert both values and execution counts. If an inactive source unexpectedly reruns the selected effect, keep the smallest reproduction, lockfile, browser version, exact command, and output. The contribution guide and reactive test source provide a concrete place to start a dependency-tracking regression.

The counts describe effect closure calls. No paint time, network latency, frame rate, whole-app performance improvement, or production scheduling behavior was measured.