@solid-primitives/immutable
Primitive for rectifying immutable values and dealing with immutability in Solid.
Installation
npm install @solid-primitives/immutable
yarn add @solid-primitives/immutable
pnpm add @solid-primitives/immutable
createImmutable
Creates a store (deeply nested reactive object) derived from the given immutable source. The source can be any signal that is updated in an immutable fashion.
It's an experimental primitive, a proof of concept of derived nested reactivity. It's not meant to be used in production, but rather as a playground for experimenting with new ideas.
How to use it
createImmutable
is a function that takes a reactive function as the first param, and an optional configuration object as the second param:
source
reactive function returning an immutable objectoptions
optional configuration
key
property name to use as unique identifier for objects when their reference changesmerge
controls how objects witohut a unique identifier are identified when reconciling an array. If true
the index is used, otherwise the object reference itself is used.
import { createImmutable } from "@solid-primitives/immutable";
const [data, setData] = createSignal({ a: 1, b: 2 });
const state = createImmutable(data);
createEffect(() => console.log(state.a, state.b));
setData({ a: 2, b: 3 });
Usage with Redux Toolkit
There are many state management libraries that provide immutable data structures, such as Immer, Redux Toolkit, XState, etc.
createImmutable
can help you turn them into reactive objects, only updating the changed values.
Warning createStore
with reconcile
will give you the similar result, while being more efficient.
import { createSlice, configureStore } from "@reduxjs/toolkit";
import { createImmutable } from "@solid-primitives/immutable";
const slice = createSlice({
initialState: [
{ id: 1, title: "Learn Solid", completed: false },
{ id: 2, title: "Learn Redux", completed: false },
],
reducers: {
},
});
const store = configureStore({
reducer: slice.reducer,
});
const [source, setSource] = createSignal(store.getState());
store.subscribe(() => setSource(store.getState()));
const todos = createImmutable(source);
<For each={todos}>
{todo => (
<div>
<input
type="checkbox"
checked={todo.completed}
onClick={() => store.dispatch(slice.actions.toggleTodo(todo.id))}
/>
{todo.title}
</div>
)}
</For>;
Usage with XState
createImmutable
doesn't mutate the source objects, as opposed to createStore
with reconcile
. This makes it a good fit for XState, which uses relies on diffing the previous and next state to determine the changes.
import { onCleanup, createSignal } from "solid-js";
import { createMachine, createActor } from "xstate";
import { createImmutable } from "@solid-primitives/immutable";
const toggleMachine = createMachine({
id: "toggle",
initial: "inactive",
states: {
inactive: {
on: { TOGGLE: "active" },
},
active: {
on: { TOGGLE: "inactive" },
},
},
});
export const Toggler = () => {
const actor = x.createActor(toggleMachine).start();
onCleanup(() => actor.stop());
const [snapshot, setSnapshot] = createSignal(actor.getSnapshot());
actor.subscribe(setSnapshot);
const state = createImmutable(snapshot);
return (
<button onclick={() => actor.send({ type: "TOGGLE" })}>
{state.value === "inactive" ? "Click to activate" : "Active! Click to deactivate"}
</button>
);
};
Usage with createResource
Data fetched from the server is immutable, so createImmutable
can help you turn it into a reactive object, only updating the changed values.
Warning createResource
provides an experimental storage
option that can be used together with createStore
and reconcile
to achieve the similar result, while being more efficient
https://www.solidjs.com/docs/latest/api#createresource
import { createResource } from "solid-js";
import { createImmutable } from "@solid-primitives/immutable";
const [data, { refetch }] = createResource(() =>
fetch("https://jsonplaceholder.typicode.com/todos/1").then(res => res.json()),
);
const state = createImmutable(data);
createEffect(() => console.log(state.title, state.completed));
refetch();
Demo
You can see the live demo here.
Source code
Changelog
See CHANGELOG.md