nanostores
Version:
A tiny (294 bytes) state manager for React/Preact/Vue/Svelte with many atomic tree-shakable stores
66 lines (58 loc) • 1.74 kB
JavaScript
import { atom, nanostoresGlobal } from '../atom/index.js'
import { onMount } from '../lifecycle/index.js'
import { warn } from '../warn/index.js'
let computedStore = (stores, cb, batched) => {
if (!Array.isArray(stores)) stores = [stores]
let previousArgs
let currentEpoch
let set = () => {
if (currentEpoch === nanostoresGlobal.epoch) return
currentEpoch = nanostoresGlobal.epoch
let args = stores.map($store => $store.get())
if (!previousArgs || args.some((arg, i) => arg !== previousArgs[i])) {
previousArgs = args
let value = cb(...args)
if (value && value.then && value.t) {
if (process.env.NODE_ENV !== 'production') {
warn(
'Use @nanostores/async for async computed. We will remove Promise support in computed() in Nano Stores 2.0'
)
}
value.then(asyncValue => {
if (previousArgs === args) {
// Prevent a stale set
$computed.set(asyncValue)
}
})
} else {
$computed.set(value)
currentEpoch = nanostoresGlobal.epoch
}
}
}
let $computed = atom(undefined)
let get = $computed.get
$computed.get = () => {
set()
return get()
}
let timer
let run = batched
? () => {
clearTimeout(timer)
timer = setTimeout(set)
}
: set
onMount($computed, () => {
let unbinds = stores.map($store => $store.listen(run))
set()
return () => {
for (let unbind of unbinds) unbind()
}
})
return $computed
}
/* @__NO_SIDE_EFFECTS__ */
export const computed = (stores, fn) => computedStore(stores, fn)
/* @__NO_SIDE_EFFECTS__ */
export const batched = (stores, fn) => computedStore(stores, fn, true)