Last active
August 8, 2022 03:20
-
-
Save mrclay/6ad71d1993e5d97e11aff1285c67eaf6 to your computer and use it in GitHub Desktop.
Minimal teaful-like store using useSyncExternalStore()
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 {useSyncExternalStore} from 'use-sync-external-store/shim'; | |
const DOT = '.'; | |
export default function createStore(defaultStore = {}) { | |
let allStore = defaultStore; | |
const listeners = new Set(); | |
function subscribe(listener) { | |
listeners.add(listener); | |
return () => listeners.delete(listener); | |
} | |
function buildSetter(path = '') { | |
let fieldPath = Array.isArray(path) ? path : path.split(DOT); | |
return (newValue) => { | |
let prevStore = allStore; | |
let value = newValue; | |
if (typeof newValue === 'function') { | |
value = newValue(getField(path)); | |
} | |
allStore = path ? | |
// Update a field | |
setField(allStore, fieldPath, value) : | |
// Update all the store | |
value; | |
}; | |
} | |
function getField(path, fn = (a, c) => a?.[c]) { | |
if (!path) return allStore; | |
return (Array.isArray(path) ? path : path.split(DOT)).reduce(fn, allStore); | |
} | |
function setField(store, [prop, ...rest], value) { | |
let newObj = Array.isArray(store) ? [...store] : {...store}; | |
newObj[prop] = rest.length ? setField(store[prop], rest, value) : value; | |
return newObj; | |
} | |
const usePath = (path = "") => { | |
const internalSetter = buildSetter(path); | |
const setter = newVal => { | |
internalSetter(newVal); | |
listeners.forEach((l) => l()); | |
}; | |
const current = useSyncExternalStore( | |
subscribe, | |
() => getField(path), | |
); | |
return [current, setter]; | |
}; | |
return {usePath}; | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment