Last active
October 26, 2022 06:04
-
-
Save trevor-atlas/32df508f6c852375a08ee9a0d2830993 to your computer and use it in GitHub Desktop.
contextless data store with react 18
This file contains hidden or 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 { useSyncExternalStore } from 'react'; | |
export function createStore<Store>( | |
creator: ( | |
set: (setter: (store: Store) => Store) => void, | |
get: () => Store | |
) => Store | |
) { | |
let store = {} as Store; | |
const get = () => store; | |
const subscribers = new Set<() => void>(); | |
const set = (next: (snapshot: Store) => Store) => { | |
if (typeof next !== 'function') { | |
throw new Error('Store updater must be a function'); | |
} | |
store = next(store); | |
subscribers.forEach((cb) => cb()); | |
}; | |
const subscribe = (callback: () => void) => { | |
subscribers.add(callback); | |
return () => subscribers.delete(callback); | |
}; | |
let initialState = creator(set, get); | |
store = { ...initialState }; | |
const useStoreData = (): { | |
get: () => Store; | |
set: (next: (snapshot: Store) => Store) => void; | |
subscribe: (callback: () => void) => () => void; | |
} => ({ | |
get, | |
set, | |
subscribe | |
}); | |
function useStore<SelectorOutput>( | |
selector: (store: Store) => SelectorOutput | |
): SelectorOutput { | |
const store = useStoreData(); | |
if (!store) { | |
throw new Error('Store not found'); | |
} | |
const state = useSyncExternalStore( | |
store.subscribe, | |
() => selector(store.get()), | |
() => selector(initialState) | |
); | |
return state; | |
} | |
return useStore; | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
use like so: