Store
The store API provides a way to create deep reactive wrappers for arbitrary objects.
The wrap
function creates a deep reactive wrapper:
import { wrap } from "rvx/store";
const state = wrap({
message: "Hello World!",
});
<h1>{() => state.message}</h1>
import { wrap, e } from "./rvx.js";
const state = wrap({
message: "Hello World!",
});
e("h1").append(() => state.message)
By default, Arrays
, Maps
, Sets
and Objects
without any or with the Object
constructor are reactive. Anything else is returned as is.
Updates
To update a reactive object, you can directly modify the wrapper.
import { wrap } from "rvx/store";
const todos = wrap([
{ name: "Foo", done: false },
{ name: "Bar", done: false },
]);
todos[1].done = true;
todos.push({ name: "Baz", done: true });
import { wrap } from "./rvx.js";
const todos = wrap([
{ name: "Foo", done: false },
{ name: "Bar", done: false },
]);
todos[1].done = true;
todos.push({ name: "Baz", done: true });
Note, that every individual update is processed immediately. To prevent this, you can use batches:
import { batch } from "rvx";
batch(() => {
todos[1].done = true;
todos.push({ name: "Baz", done: true });
});
import { batch } from "./rvx.js";
batch(() => {
todos[1].done = true;
todos.push({ name: "Baz", done: true });
});
Signal Reflection
The reflect
utility can be used to create a signal that reflects a reactive property of an arbitrary object.
import { reflect, wrap } from "rvx/store";
const item = wrap({ name: "Foo", done: false });
const done = reflect(item, "done");
import { reflect, wrap } from "./rvx.js";
const item = wrap({ name: "Foo", done: false });
const done = reflect(item, "done");
The target object doens't need to be a reactive wrapper. Any arbitrary object with reactive properties works.
Classes
By default, arbitrary class instances are not reactive unless you specify, how to wrap them:
import { wrapInstancesOf } from "rvx/store";
class Example {
static {
// Wrap instances of "Example" in the same way, objects are wrapped:
wrapInstancesOf(this);
// Or implement custom behavior:
wrapInstancesOf(this, target => {
return new Proxy(target, ...);
});
}
}
import { wrapInstancesOf } from "./rvx.js";
class Example {
static {
// Wrap instances of "Example" in the same way, objects are wrapped:
wrapInstancesOf(this);
// Or implement custom behavior:
wrapInstancesOf(this, target => {
return new Proxy(target, ...);
});
}
}
Private Fields
Private fields are not reactive. Also, you need to ensure they are accessed through the original object instead of reactive wrappers by using unwrap
.
import { wrapInstancesOf, wrap, unwrap } from "rvx/store";
class Example {
static {
wrapInstancesOf(this);
}
#count = 0;
thisWorks() {
// "unwrap" always returns the original object
// or the value itself if it isn't a wrapper:
unwrap(this).#count++;
}
thisFails() {
// This will fail, since "this" refers to the
// reactive wrapper instead of the original object:
this.#count++;
}
}
const example = wrap(new Example());
example.thisWorks();
example.thisFails();
import { wrapInstancesOf, wrap, unwrap } from "./rvx.js";
class Example {
static {
wrapInstancesOf(this);
}
#count = 0;
thisWorks() {
// "unwrap" always returns the original object
// or the value itself if it isn't a wrapper:
unwrap(this).#count++;
}
thisFails() {
// This will fail, since "this" refers to the
// reactive wrapper instead of the original object:
this.#count++;
}
}
const example = wrap(new Example());
example.thisWorks();
example.thisFails();