这个系列是将 ahooks 里面的所有 hook 源码都进行解读,通过解读 ahooks 的源码来熟悉自定义 hook 的写法,提高自己写自定义 hook 的能力,希望能够对大家有所帮助。
今天解读 Advanced 部分的最后两个 hook。
往期回顾
useReactive
享受Vue的开发快感~
import { useRef, useState } from 'react';
import useCreation from '../useCreation';
// k:v 原对象:代理过的对象
const proxyMap = new WeakMap();
// k:v 代理过的对象:原对象
const rawMap = new WeakMap();
function isObject(val: object): boolean {
return typeof val === 'object' && val !== null;
}
/// 初始化的时候对目标进行深度监听,发生变更时通知 cb
function observer<T extends object>(initialVal: T, cb: () => void): T {
const existingProxy = proxyMap.get(initialVal);
// 添加缓存 防止重新构建proxy
if (existingProxy) {
return existingProxy;
}
// 防止代理已经代理过的对象
// https://github.com/alibaba/hooks/issues/839
if (rawMap.has(initialVal)) {
return initialVal;
}
/// 使用 Proxy 实现变化监听。Vue3.x:我我我?
const proxy = new Proxy<T>(initialVal, {
get(target, key, receiver) {
/// Reflect 也是 ES6 引入的更优雅的操作对象的api
const res = Reflect.get(target, key, receiver);
return isObject(res) ? observer(res, cb) : Reflect.get(target, key);
},
set(target, key, val) {
const ret = Reflect.set(target, key, val);
cb();
return ret;
},
deleteProperty(target, key) {
const ret = Reflect.deleteProperty(target, key);
cb();
return ret;
},
});
proxyMap.set(initialVal, proxy);
rawMap.set(proxy, initialVal);
return proxy;
}
/// 对初始化数据进行深度监听,如果有变更则触发重新渲染
function useReactive<S extends object>(initialState: S): S {
const [, setFlag] = useState({});
const stateRef = useRef<S>(initialState);
const state = useCreation(() => {
return observer(stateRef.current, () => {
/// 设置一个新对象触发重新渲染
setFlag({});
});
}, []);
return state;
}
export default useReactive;
复制代码
useSafeState
带了“保镖“的 useState
用法与 React.useState 完全一样,但是在组件卸载后异步回调内的 setState 不再执行,避免因组件卸载后更新状态而导致的内存泄漏
import React, { Dispatch, SetStateAction } from 'react'
import useUnmountedRef from '../useUnmountedRef'
function useSafeState<S>(initialState: S | (() => S)): [S, Dispatch<SetStateAction<S>>]
function useSafeState<S = undefined>(): [S | undefined, Dispatch<SetStateAction<S | undefined>>];
function useSafeState(initialState?) {
const unmountedRef = useUnmountedRef()
const [state, setState] = React.useState(initialState)
const setCurrentState = (currentState) => {
/** 如果组件已经卸载则不再更新 state */
if (unmountedRef.current) return
setState(currentState)
}
return [state, setCurrentState] as const
}
export default useSafeState
复制代码
以上内容由于本人水平问题难免有误,欢迎大家进行讨论反馈。
© 版权声明
文章版权归作者所有,未经允许请勿转载。
THE END