reactive-signals

reactive-signals is a dx-first scope-based fine grained reactive system. It is based on the excellent ideas in leptos_reactive but is written from scratch to provide the simplest API and mental model possible for developers.

This documentation assumes that you know Leptos and are familiar with the concepts of reactivity. - TBD (to be done) means that the feature will be added in the future. - TBC (to be confirmed) means that it is a possible future addition

Note: This project is not yet ready for use! It needs a full test coverage first.

Features

Example

```rust ignore use reactive_signals::{signal, Scope, Scoped, runtimes::ClientRuntime};

enum UserActions { None, StartClicked, PlusClicked, MinusClicked, TextChanged(String), }

// Let's do a simple "select your fruit and quantity in 30 seconds" app.

// The entire app needs to know which fruit and the quantity

[derive(Default, Scoped)]

struct FruitSelection((Option, usize));

// create a root scope. let sc = ClientRuntime::newrootscope();

// let's attach the FruitSelection to the scope let sc = FruitSelection((String, 0)).attach_to(sc);

// Run the app. fruitlistapp(sc);

fn fruitlistapp( sc: FruitSelectionScope, actions: Signal, RT>, displayed: Signal, RT>) {

let secsremaning = signal!(sc, 30); let count = signal!(sc, 0); let name = signal!(sc, Option::::None); let fruithistory = signal!(sc, Vec::::new())

let running = signal!(sc, false);

signal!(sc, move || { match actions.get() { UserActions::StartClicked if !running.get() => { running.set(true); signal!(sc, 1 sec, async move |&mut interval| { if secsremaining.get() <= 0 { running.set(false); interval = None; // stop running intsc.dispose(); // one of the few times you'll need to dispose a scope manually } else { secs_remaning.update(|s| *s += 1); } }); } UserActions::PlusClicked => count.update(|c| *c += 1), UserActions::MinusClicked if count.get() > 0 => count.update(|c| *c -= 1), UserActions::TextChanged(txt) => name.set(txt), _ => {} } }); } ```

Cargo features

Evolutions

Benchmarks

Measurements have been rounded for ease of reading and reasoning. They measure ScopeInner and SignalInner (not part of public API) which are where the data is stored as Scope and Signal only has index (integer) data

Performance

These measurements have been produced using criterion by measuring on 1000 instances and calculating the time for one. It has been measured on a Macbook M1.

| What | Time | With unsafe-cell | --- | --- | --- | Create a ScopeInner | 10 ns | 8 ns | Create a SignalInner | 55 ns | 50 ns | Notify a subscriber | 25 ns | 15 ns

The leptos_reactive profiling example "Leptos create 1000 signals" measures 245 µs. The same measures 70 µs using reactive-signals. That makes for a 3.5 times improvement.

Memory use

These measurements has been produced using dhat by creating 1000 instances and calculating the size of one.

| What | Heap use | With unsafe-cell | --- | --- | --- | ScopeInner | 40 bytes | 32 bytes | SignalInner | 80 bytes | 70 bytes | Subscription* | 8 bytes | 12 bytes

* The memory use for each signal subscription.

In leptosreactive, 1000 signals and one memo uses 400kb and in reactive-signals creating 1000 function signals each with a subscription uses 100kb. In other words, reactive-signals use 4 times less memory than leptosreactive

Please see the benches, examples and tests for full details.

A personal note & the future of reactive-signals

I have spent a lot of time on reactive-signals which have been entirely self-funded. Unfortunately, I cannot continue like that (I would love to, though!).

The future of reactive-signals depends on you and if you want to fund the features listed with a TBC.

I have created a fundraiser for it.

I'm open to any type of freelance contract work that would allow me to continue developing and maintaining the open-source projects I have and plan to do. See my services.

See my other open-source projects.

Feel free to reach out if you are interested!