前端面试复习系列之react-hooks

1,124 阅读1分钟

监听深度依赖的值变化

借助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一样,脏活累活都包装了起来,外部只需要优雅的调用,不用过多关心细节,你卯足了劲撸代码就完事儿👌

参考资料: