Last active
May 14, 2023 01:36
svelte-zustand (adapter)
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
import { toSvelteStore, useStore } from './svelte-zustand-adapter'; | |
import { createStore } from 'zustand'; | |
import { combine } from 'zustand/middleware'; | |
import { immer } from 'zustand/middleware/immer'; | |
const getDefaultInitialState = (): State => ({ | |
data: null, | |
}); | |
const initializeStore = (preloadedState: Partial<State> = {}) => | |
createStore( | |
immer( | |
combine( | |
{ | |
...getDefaultInitialState(), | |
...preloadedState, | |
} as State, | |
(set) => | |
({ | |
setData: (payload) => { | |
set((state) => { | |
state.data = payload; | |
}); | |
}, | |
removeData: () => { | |
set((state) => { | |
state.data = getDefaultInitialState().data; | |
}); | |
}, | |
} as Actions), | |
), | |
), | |
); | |
export const store = toSvelteStore(initializeStore()); | |
// SELECTORS | |
const getAbcData = (state: ModuleState) => state.data; | |
// "REACT HOOK"-ALIKE HELPER FUNCTONS | |
export const useAbcStore = <T>( | |
selector?: Parameters<typeof useStore<typeof store, T>>[1], | |
) => useStore(accountStore, selector); | |
export const useAbcData = () => useAbcStore(getAbcData); | |
export const useSetData = () => useAbcStore((state) => state.setData); | |
// TYPES | |
interface State { | |
data: { | |
id: number; | |
//... | |
} | null; | |
} | |
interface Actions { | |
setData: (payload: State['data']) => void; | |
removeData: () => void; | |
} | |
type ModuleState = State & Actions; | |
// type ModuleStore = ReturnType<typeof createStore<ModuleState, [['zustand/immer', never]]>>; // add `['zustand/subscribeWithSelector', never]` if you use `zustand/middleware/subscribeWithSelector` |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
import { readable, type Readable } from 'svelte/store'; | |
import type { useStore as _useStore, StoreApi } from 'zustand'; | |
// inspired by https://jfranciscosousa.com/blog/using-zustand-with-svelte/ | |
export function toSvelteStore<Store extends StoreApi<StateType>, StateType>(zustandStore: Store) { | |
const svelteStore = readable(zustandStore.getState(), (set) => { | |
zustandStore.subscribe((value) => set(value)); | |
}); | |
return { | |
...zustandStore, | |
...svelteStore, | |
subscribe: svelteStore.subscribe, | |
zustandSubscribe: zustandStore.subscribe, | |
} as Readable<ReturnType<Store['getState']>> & | |
Store & { | |
zustandSubscribe: Store['subscribe']; | |
}; | |
} | |
// inspired by https://github.com/JoaoPauloLousada/ngx-zustand | |
export function useStore<S extends StoreApi<StateType>, T, StateType = unknown>( | |
store: S, | |
selector?: Parameters<typeof _useStore<S, T>>[1], | |
// equalityFn?: Parameters<typeof _useStore<S, T>>[2], // this arg is only available with original React hook `useStore` exported from `zustand` | |
): T; | |
export function useStore<S extends StoreApi<unknown>>( | |
store: Parameters<typeof _useStore<S>>[0], | |
): ReturnType<typeof _useStore<S>>; | |
export function useStore<S extends StoreApi<StateType>, T, StateType>( | |
store: Parameters<typeof _useStore<S, T>>[0], | |
selector?: Parameters<typeof _useStore<S, T>>[1], | |
) { | |
const state = store.getState(); | |
return selector ? selector(state as Parameters<Parameters<typeof _useStore<S, T>>[1]>[0]) : state; | |
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
<script lang="ts"> | |
import { store, useAbcData, useSetData } from './store'; | |
// you can import store & access its prop directly: | |
$: console.log('new changes will be logged here', $store.data); | |
// or grab its data via helper function: | |
const data = useAbcData(); // note that `data` is not subscribed to changes (like it should be if returned from a "react hook"). If you need to, use `$store.data` instead | |
const setData = useSetData(); // same goes here | |
</script> | |
<button on:click={() => { | |
store.getState().setData({ | |
id: Math.random(), | |
}); | |
// OR: | |
// setData({ | |
// id: Math.ramdom(), | |
// }); | |
}}> | |
Set random data | |
</button> | |
{$store.data} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment