V2EX = way to explore
V2EX 是一个关于分享和探索的地方
现在注册
已注册用户请  登录
huijiewei
V2EX  ›  React

React Hook 一些实践选择的讨论

  •  
  •   huijiewei ·
    huijiewei · 2022-08-10 22:54:40 +08:00 · 2302 次点击
    这是一个创建于 596 天前的主题,其中的信息可能已经有所发展或是发生改变。

    目前我正在实现自己的一个组件库: https://agile-ui.vercel.app/

    里面用到了 useFocus, useHover 等等自定义的 Hook

    目前这种机制的 Hook 有两种实现方式:

    第一种: 传入原始的 onBlur, onFocus 事件,然后合并事件并返回 handle ,在组件里面使用 on 绑定:

    
    export const useFocus = (options) => {
      const { state = false, onBlur, onFocus } = options;
    
      const [focus, setFocus] = useState(state);
    
      const handleBlur = useCallback(
        (e) => {
          setFocus(false);
          onBlur && onBlur(e);
        },
        [onBlur]
      );
    
      const handleFocus = useCallback(
        (e) => {
          setFocus(true);
          onFocus && onFocus(e);
        },
        [onFocus]
      );
    
      return { focus, handleBlur, handleFocus };
    }
    
    export const Demo = (props) => {
    	const { onBlur, onFocus, ...rest } = props;
        
        const { focus, handleBlur, handleFocus } = useFocus({ onBlur, onFocus });
        
        return <button onBlur={handleBlur} onFocus={handleFocus} {...rest} />
    }
    
    

    第二种:利用 ref 绑定事件即可,不需要传递事件

    
    export const useFocus = () => {
      const [focus, setFocus] = useState(false);
      const ref = useRef(null);
      const handleBlur = useCallback(() => setFocus(false), []);
      const handleFocus = useCallback(() => setFocus(true), []);
    
      useEffect(() => {
        if (ref.current) {
          ref.current.addEventListener('blur', handleBlur);
          ref.current.addEventListener('focus', handleFocus);
    
          return () => {
            ref.current?.removeEventListener('blur', handleBlur);
            ref.current?.removeEventListener('focus', handleFocus);
          };
        }
    
        return undefined;
      }, []);
    
      return { ref, focus };
    }
    
    
    export const Demo = (props) => {
        const { ref, focus } = useFocus();
        
        return <button ref={ref} {...props} />
    }
    
    

    大家觉得哪种方案更好呢?

    7 条回复    2022-08-11 12:31:33 +08:00
    XCFOX
        1
    XCFOX  
       2022-08-10 23:01:53 +08:00
    ref ,并且这个 ref 得支持从外部传入。

    如果返回 bind 绑定的话,可能会出现多个 hook 的 bind 对应到同一个 element 的同一个事件。
    比如 useDrag() 和 useHover() 同时绑定了目标元素的 onMouseEnter 事件。
    Leviathann
        2
    Leviathann  
       2022-08-10 23:31:10 +08:00
    目前业内用的比较多的是 2
    runtousa
        3
    runtousa  
       2022-08-11 08:30:21 +08:00 via iPhone
    文档写的挺好的
    dog
        4
    dog  
       2022-08-11 08:56:10 +08:00
    可以看看 ahooks ,他们实现了很多自定义的 hook
    https://github.com/alibaba/hooks
    Mutoo
        5
    Mutoo  
       2022-08-11 09:48:34 +08:00
    第一种更容易 compose handle functions ,如果用户需要额外的逻辑的话,第二种就没办法实现了。
    huijiewei
        6
    huijiewei  
    OP
       2022-08-11 12:04:21 +08:00
    感谢大家的回复。最终使用第二种方案,利用 useMergeRefs 的能力,合并 handle 也非常简单
    juneszh
        7
    juneszh  
       2022-08-11 12:31:33 +08:00
    ref
    关于   ·   帮助文档   ·   博客   ·   API   ·   FAQ   ·   我们的愿景   ·   实用小工具   ·   1200 人在线   最高记录 6543   ·     Select Language
    创意工作者们的社区
    World is powered by solitude
    VERSION: 3.9.8.5 · 26ms · UTC 23:13 · PVG 07:13 · LAX 16:13 · JFK 19:13
    Developed with CodeLauncher
    ♥ Do have faith in what you're doing.