InfiniteXyy/zoov

Support for Async Listeners

theskinnycoder opened this issue · 2 comments

We started using this library at work, and we were wondering if it is possible to add subscriptions to the whole store or a specific state variable. Maybe something like this :

const { use: useCounter } = defineModule({ count: 0 })
  .actions({
    add: (draft) => draft.count++,
    minus: (draft) => draft.count--,
  })
  .computed({
    doubled: (state) => state.count * 2,
  })
  .listen(async (store) => {
    await fetch("/api/put-request", {
      method: "PUT",
	  body: {
	    data: store
      }
    })
  })
  .build();

Thank you for your suggestion! I'm working on the new api for v0.5.0. Hope it will come out today😄

Currently, maybe you can use computed as a workaround

Hi @theskinnycoder
A new version is released with subscribe support!

We can now trigger network requests on property change.

The sample code is like

const module = defineModule({ pokemonIndex: 0, input: '' })
  .subscribe((state, prevState) => console.log(state)) // subscribe to the whole store
  .subscribe({
    selector: (state) => state.pokemonIndex, // only subscribe to some property
    listener: async ({ pokemonIndex }, prev, { addCleanup }) => {
      const abortController = new AbortController();
      const abortSignal = abortController.signal;
      addCleanup(() => abortController.abort()); // if you want to abort the previous promise, like switchMap in rxjs
      const response = await fetch(`https://pokeapi.co/api/v2/pokemon/${pokemonIndex}`, { signal: abortSignal });
      console.log(await response.json());
    },
  })
  .build();

But there is some limitation, because module are globally initialized, zoov will never destroy a module or unsubscribe the listeners.

If you want to get better control over subscription lifecycle, you can call the original zustand subscribe API, and unsubscribe it on demand.

The zustand store can be retrieved via module.getStore() or module.useStore()

const store = module.useStore()

useEffect(() => {
    const unsubscribe = store.subscribe(() => {});
    return unsubscribe;
}, [])