Releases: riccardoperra/statebuilder
[email protected]
Patch Changes
- 321645c: fix reactivity - add solid exports
[email protected]
Patch Changes
- 46892dd: add before event to command plugin
[email protected]
Minor Changes
- 3ce5a15: - States will now get resolved using their Container reactive context instead of the context where they are defined.
- Errors thrown through the state lifecycle will return a
StateBuilderError
class. - Add the
remove
method to the Container API to destroy a state - Add container hierarchy
- Export
ɵdefineResource
andɵWithResourceStorage
state resource API
- Errors thrown through the state lifecycle will return a
[email protected]
Minor Changes
-
8d627ba: feat: allow to inject states inside builders
Since this version, you can inject other states into plugins (
.extend
).const AppState = defineSignal(() => ({})); const CounterState = defineSignal(() => 1).extend((_, context) => { const appState = context.inject(AppState); });
[email protected]
[email protected]
What's Changed
- missing esm exports in statebuilder package
Full Changelog: https://github.com/riccardoperra/statebuilder/compare/[email protected]@0.4.2
[email protected]
What's Changed
- fix: refactor command listener with @solid-primitives/event-bus by @riccardoperra in #23
Full Changelog: https://github.com/riccardoperra/statebuilder/compare/[email protected]@0.4.1
[email protected]
What's new
State plugin hooks - #20
With [email protected], the core system will now support some initialization hooks
under the hood:
- onInit: it runs when your store state initialises, after all given plugins have been applied.
- onDestroy: it runs when the reactive owner is disposed.
You can access these hooks while creating a plugin or while defining a store extension through the .extend()
method. Hooks are basically registered callbacks in a queue system and they will be applied in order.
const myPlugin = makePlugin((state, context) => {
context.hooks.onInit(() => console.log('run on state init'));
context.hooks.onDestroy(() => console.log('run on state destroy'));
}, { name: 'myPlugin' });
createRoot(dispose => {
const container = Container.create();
const CountState = defineSignal(() => 0)
.extend(myPlugin);
const count = container.get(CountState);
// ✅ onInit hook will run
container.get(CountState);
// ❌ onInit hook will not run anymore: state is already initialised
dispose();
// ✅ onDestroy hook will run
})
State support for solid-js createResource
- #22
This new version add support for creating StateBuilders state definitions using solid-js createResource
under the hood. It's now marked as experimental feature.
The state built with this new api will return basically a Resource which uses the mutate
function under the hood as store setter
. It acts like a wrapper but with the support of StateBuilder plugin extension and hook system.
import { experimental__defineResource } from 'statebuilder';
const TodoAsyncState = experimental__defineResource(
() => fetch('https://jsonplaceholder.typicode.com/todos/1').then(response => response.json())
).extend(() => {
// ...
});
const todoState = container.get(TodoAsyncState);
// ˆ? todoState: Resource<Todo> & { set: Setter<Todo>, refetch(init?: unknown): void }
statebuilder/commands drop support for RxJS - #17
Since this version, the command
plugin will not use anymore RxJS to handle the command event state. Instead, it will use directly the solid-js signal based system.
Since Solid handle signals like RxJS BehaviorSubject
, and the previous implementation had an attached Subject
under the hood, the code for watching the commands events should change.
Since the watchCommand
method will now return an Accessor<Command>
instead of a BehaviorSubject
, In order to avoid to run the callback before receiving your watched commands, you can mix the createEffect
with the on
utility.
Before:
interface Commands {
add: number;
}
const CountStore = defineSignal(() => 0)
.extend(withProxyCommands<Commands>())
.extend(state => {
const watch$ = state.watchCommand([state.commands.add]);
// ˆ? watch$: Observable<StateCommand<'add', number>>
watch$.subscribe((x) => console.log(x))
})
After:
import {createEffect, on} from 'solid-js';
interface Commands {
add: number;
}
const CountStore = defineSignal(() => 0)
.extend(withProxyCommands<Commands>())
.extend(state => {
const watched = state.watchCommand([state.commands.add]);
// ˆ? watched: Accessor<StateCommand<'add', number>>
createEffect(on(watched, command => {
console.log(command);
}))
})
What's Changed
- perf: refactor commands plugin removing RxJS by @riccardoperra in #17
- feat: add store definition init/destroy hooks. support local owner by @riccardoperra in #20
- test: hooks by @riccardoperra in #21
- feat: command devtools by @riccardoperra in #19
- feat: store resource by @riccardoperra in #22
- chore: update versions by @github-actions in #18
Full Changelog: https://github.com/riccardoperra/statebuilder/compare/[email protected]@0.4.0
[email protected]
Patch Changes
- 16fffae: perf: improve type resolution performance
[email protected]
Breaking changes
This new version removes withPlugin
introduced in 0.2.4. Instead, now plugins will infer automatically the type, and uses a generic signatureby default.
const store = defineSignal(() => 1).extend(
withProxyCommands<{increment: boolean}>())
);
store.hold(
store.commands.increment,
(command, { set }) => {
// ✅ Now `set` is Setter<number> instead of (...args: any) => void
set(v => v + 1);
});
Create plugins with store constraints
In order to create plugins that must follow a specific store signature, you can now use the .typed
helper of makePlugin function.
const pluginOnlyForStoreLike = () => makePlugin.typed<Store<{ count: number }>>()(store => {
// ...
});
// ❌ pluginOnlyForStoreLike cannot be used anymore since store does not follow the { count : number } state signature
const store1 = defineStore(0).extend(pluginOnlyForStoreLike())
What's Changed
- feat: refactor types for implicit inference by @riccardoperra in #13
- chore: update versions by @github-actions in #14
Full Changelog: https://github.com/riccardoperra/statebuilder/compare/[email protected]@0.3.0