Skip to content
Compare
Choose a tag to compare
@riccardoperra riccardoperra released this 02 Apr 14:27
· 79 commits to main since this release
f5fb9eb

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 commandplugin 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

Full Changelog: https://github.com/riccardoperra/statebuilder/compare/[email protected]@0.4.0