监听深度依赖的值变化
借助lodash的isEqual实现
import { isEqual } from 'lodash';
function useDeepCompareEffect(fn, deps){
const comparisons = useRef(0);
const prevDeps = useRef(deps);
if(!isEqual(prevDeps.current, deps)){
comparisons.current++;
}
prevDeps.current = deps;
return useEffect(fn, [comparisons.current]);
}
自动取消api请求
借助AbortController类控制fetch方法的signal字段,AbortController.signal标记一次请求,在合适的时候调用AbortController.abort()取消该次请求,查看浏览器兼容性
export function useFetch = (config, deps) => {
const abortController = new AbortController()
const [loading, setLoading] = useState(false)
const [result, setResult] = useState()
useEffect(() => {
setLoading(true)
fetch({
...config,
signal: abortController.signal
})
.then((res) => setResult(res))
.finally(() => setLoading(false))
}, deps)
useEffect(() => {
return () => abortController.abort()
}, [])
return { result, loading }
}
setState过后立即获取新值
由于react内部的状态更新机制,在同一个代码块内,setState后是无法立即获取到新值的,class组件里面可以通过回调函数,或者利用setTimeout之类跳出当前try块从而获取新值,为了更方便的获取值,可以利用useRef
.current
值可变但是在组件整个生命周期内保持不变的特性,实现一个桥梁
export const useRefState = <T>(
initialValue: T
): [React.MutableRefObject<T>, React.Dispatch<React.SetStateAction<T>>, T] => {
const [state, setState] = useState<T>(initialValue);
const refState = useRef(state);
useEffect(() => {
refState.current = state;
}, [state]);
return [refState, setState, state];
}
定时器
借助useRef的特性,所以也可以实现定时器的控制
export const useTimeout = useCallback((callback: any, timeout: number = 3000) => {
let callbackRef = useRef<any>();
useEffect(() => {
callbackRef.current = callback;
});
useEffect(() => {
let id = setTimeout(() => callbackRef.current && callbackRef.current(), timeout);
return () => clearTimeout(id);
}, [timeout])
}, [])
当自己尝试写过几个自定义的hook之后,想必都能感受到hook给开发者带来的便利,这种感觉就像写了一个逻辑层面的jsx一样,脏活累活都包装了起来,外部只需要优雅的调用,不用过多关心细节,你卯足了劲撸代码就完事儿👌
参考资料: