Skip to content

Instantly share code, notes, and snippets.

@vikiboss
Created April 4, 2023 11:24
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save vikiboss/52302b962809f5682d38cccf3d7e0b0f to your computer and use it in GitHub Desktop.
Save vikiboss/52302b962809f5682d38cccf3d7e0b0f to your computer and use it in GitHub Desktop.
响应式状态 Demo
import rfdc from 'rfdc'
type Listener<T> = (snapshot: T) => void
interface State<T extends object> {
proxy: T
target: T
listeners: Set<Listener<T>>
}
const deepClone = rfdc()
const stateMap = new WeakMap<object, State<any>>()
function createState<T extends object>(initialObject: T): T {
const createStateRecursive = <U extends object>(obj: U): U => {
const handler: ProxyHandler<U> = {
get(target, prop, receiver) {
const value = Reflect.get(target, prop, receiver)
if (typeof value === 'object' && value !== null) {
return createStateRecursive(value)
}
return value
},
set(target, prop, value, receiver) {
if (!Reflect.has(target, prop) || !Object.is(Reflect.get(target, prop, receiver), value)) {
Reflect.set(target, prop, value, receiver)
notifyUpdate(state)
}
return true
}
}
return new Proxy<U>(obj, handler)
}
const proxyObject = createStateRecursive(initialObject)
const state: State<T> = {
proxy: proxyObject,
target: initialObject,
listeners: new Set<Listener<T>>()
}
stateMap.set(proxyObject, state)
return proxyObject
}
function subscribe<T extends object>(proxyObject: T, listener: Listener<T>): () => void {
const state = stateMap.get(proxyObject)
if (!state) {
console.warn('Please use a proxy object.')
return () => {}
}
state.listeners.add(listener)
const unsubscribe = () => {
state.listeners.delete(listener)
}
return unsubscribe
}
function snapshot<T extends object>(proxyObject: T): T {
const state = stateMap.get(proxyObject)
if (!state) {
console.warn('Please use a proxy object.')
return {} as T
}
return deepClone(state.target) as T
}
function notifyUpdate<T extends object>(state: State<T>): void {
const currentSnapshot = snapshot(state.proxy)
state.listeners.forEach(listener => {
listener(currentSnapshot)
})
}
export { createState, subscribe, snapshot }
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment