ahooks 源码解读系列 – 3

这个系列是将 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
喜欢就支持一下吧
点赞0 分享