用过vue的人都知道我们改变data里面的数据,直接改变原属性值就可以达到页面更新视图的效果,那么我们在react里面也实现一个类似的hook。
useReactive
提供一种数据响应式的操作体验,定义数据状态不需要写
useState,直接修改属性即可刷新视图。
思路
-
创建函数
-
export const useReactive = <S extends Record<string, any>>(initialState: S): S => { return initialState; }; -
通过proxy代理数据劫持
-
创建observer(观察者函数)
-
export const useReactive = <S extends Record<string, any>>(initialState: S): S => { function observer<T extends Record<string, any>>(initialVal: T, cb: () => void): T { return initialVal } return initialState; }; -
创建proxy对象
-
export const useReactive = <S extends Record<string, any>>(initialState: S): S => { function observer<T extends Record<string, any>>(initialVal: T): T { const proxy = new Proxy(initialVal, { get(target: T, p: string | symbol, receiver: any): any { const res = Reflect.get(target, p, receiver); return res; }, set(target: T, p: string | symbol, receiver: any): boolean { const res = Reflect.get(target, p, receiver); return res; }, defineProperty(target: T, p: string | symbol, attributes: PropertyDescriptor): boolean { const res = Reflect.defineProperty(target, p, attributes); return res; }, }); return proxy; } const state = observer(initialState) return state; };
-
-
测试函数,哈哈哈其实这个时候还没写完,还有好多bug
-
我们先让hook能正常使用
-
export const useReactive = <S extends Record<string, any>>(initialState: S): S => { const [, setState] = useState({}); function observer<T extends Record<string, any>>(initialVal: T, cb: () => void): T { const proxy = new Proxy(initialVal, { get(target: T, key: string | symbol, receiver: any): any { const res = Reflect.get(target, key, receiver); return isObject(res) ? observer(res, cb) : Reflect.get(target, key, receiver); }, set(target: T, key: any, receiver: any): boolean { const ret = Reflect.set(target, key, receiver); cb(); return ret; }, defineProperty(target: T, key: string | symbol, attributes: PropertyDescriptor): boolean { const ret = Reflect.defineProperty(target, key, attributes); cb(); return ret; }, }); return proxy; } const stateRef = useRef<S>(initialState); const state = observer(stateRef.current, () => { // 重新render 保证页面刷新 setState({}); }); return state; }; -
至此我们的useReactive可以正常的运行了
-
-
-
试试对象
-
-
-
都能正常运行
优化
-
我们现在每次更改数据都会创建一个proxy,利用闭包缓存。
-
export const useReactive = <S extends Record<string, any>>(initialState: S): S => { // 更新视图 const [, setState] = useState({}); // 代理对象 const proxyMap = new WeakMap(); function observer<T extends Record<string, any>>(initialVal: T, cb: () => void): T { const cacheProxy = proxyMap.get(initialVal); if (cacheProxy) return cacheProxy; const proxy = new Proxy(initialVal, { get(target: T, key: string | symbol, receiver: any): any { const res = Reflect.get(target, key, receiver); return isObject(res) ? observer(res, cb) : Reflect.get(target, key, receiver); }, set(target: T, key: any, receiver: any): boolean { const ret = Reflect.set(target, key, receiver); cb(); return ret; }, defineProperty(target: T, key: string | symbol, attributes: PropertyDescriptor): boolean { const ret = Reflect.defineProperty(target, key, attributes); cb(); return ret; }, }); proxyMap.set(initialVal, proxy); return proxy; } const stateRef = useRef<S>(initialState); return observer(stateRef.current, () => { // 重新render 保证页面刷新 setState({}); }); }; -
完结撒花!!!