@everystate/solid 1.0.1
Solid adapter for @everystate/core. Four functions - the entire API. ~30 lines.
See a complete task manager: Solid Example
Install
npm install @everystate/solid @everystate/core
Peers: solid-js >=1.6.0, @everystate/core >=1.0.5.
Quick Start
import { createEveryState } from '@everystate/core';
import { usePath, useIntent } from '@everystate/solid';
const store = createEveryState({ state: { count: 0 } });
store.subscribe('intent.increment', () => {
store.set('state.count', store.get('state.count') + 1);
});
function Counter() {
const count = usePath(store, 'state.count');
const inc = useIntent(store, 'intent.increment');
return <button onClick={() => inc(true)}>{count()}</button>;
}
usePath(store, path)
Read-only Solid accessor. Updates when store value changes. Fine-grained by default - only computations reading this accessor re-run.
const count = usePath(store, 'state.taskCount');
const items = usePath(store, 'derived.tasks.filtered');
useIntent(store, path)
Stable setter function. Publishes intent to the store.
const add = useIntent(store, 'intent.addTask');
const toggle = useIntent(store, 'intent.toggleTask');
useWildcard(store, path)
Re-runs when any child of the path changes.
const user = useWildcard(store, 'state.user.*');
useAsync(store, path)
Async lifecycle with auto-abort. Each field is a Solid accessor.
const { data, status, execute } = useAsync(store, 'users');
execute((signal) => fetch('/api/users', { signal }).then(r => r.json()));
Context Pattern (Optional)
Unlike React/Vue where the provider is essentially required, in Solid passing the store as a prop is perfectly idiomatic. But if you prefer DI:
import { createContext, useContext } from 'solid-js';
const StoreContext = createContext();
function App() {
const store = createEveryState({ state: { count: 0 } });
return (
<StoreContext.Provider value={store}>
<Counter />
</StoreContext.Provider>
);
}
function useStore() { return useContext(StoreContext); }
Three Namespaces
| Namespace | Purpose | Function |
|---|---|---|
state.* | Application state | usePath |
derived.* | Computed projections | usePath |
intent.* | UI signals | useIntent |
Fine-Grained Updates
Solid has no virtual DOM. When usePath returns an accessor that changes, only the exact DOM expression reading it updates. No diffing, no reconciliation, no component re-renders. This is the most efficient bridge possible - EveryState fires per-path, Solid updates per-signal.
Testing Without Solid
test('add task increments count', () => {
const store = createEveryState({ state: { tasks: [], taskCount: 0 } });
store.subscribe('intent.addTask', (text) => {
const tasks = store.get('state.tasks') || [];
const next = [...tasks, { text, done: false }];
store.set('state.tasks', next);
store.set('state.taskCount', next.length);
});
store.set('intent.addTask', 'test');
expect(store.get('state.taskCount')).toBe(1);
});
No createRoot. No renderToString. Just state in, state out.