-
Notifications
You must be signed in to change notification settings - Fork 1
/
venti.js
55 lines (48 loc) · 1.3 KB
/
venti.js
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
import { useState, useEffect } from 'react'
import State from 'state-eventer'
export { State }
function pathToString(path) {
if (typeof path === 'string') return path
if (Array.isArray(path)) return path.join('.')
throw new Error('state.get: `path` must be a string or array')
}
class InstrumentedState {
constructor(state) {
this.state = state
this.paths = {}
}
get(path, defaultValue) {
const pathString = pathToString(path)
this.paths[pathString] = true
return this.state.get(path, defaultValue)
}
set(path, value) {
return this.state.set(path, value)
}
update(path, fn, defaultValue) {
return this.state.update(path, fn, defaultValue)
}
unset(path) {
return this.state.unset(path)
}
}
export const state = new State()
export function useVenti(customState) {
const globalState = customState || state
const instrumentedState = new InstrumentedState(globalState)
const [, forceUpdate] = useState(null)
useEffect(() => {
let listeners = []
Object.keys(instrumentedState.paths).forEach(path => {
const listener = state.on(path, event => {
forceUpdate({})
})
listeners.push(listener)
})
return () => {
listeners.forEach(listener => listener.off())
listeners = []
}
})
return instrumentedState
}