目前我正在实现自己的一个组件库: 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} /> }
大家觉得哪种方案更好呢?
![]() | 1 XCFOX 2022-08-10 23:01:53 +08:00 ref ,并且这个 ref 得支持从外部传入。 如果返回 bind 绑定的话,可能会出现多个 hook 的 bind 对应到同一个 element 的同一个事件。 比如 useDrag() 和 useHover() 同时绑定了目标元素的 onMouseEnter 事件。 |
2 Leviathann 2022-08-10 23:31:10 +08:00 目前业内用的比较多的是 2 |
3 runtousa 2022-08-11 08:30:21 +08:00 via iPhone 文档写的挺好的 |
![]() | 4 6j1A6v70lEv5n2U2 2022-08-11 08:56:10 +08:00 可以看看 ahooks ,他们实现了很多自定义的 hook https://github.com/alibaba/hooks |
![]() | 5 Mutoo 2022-08-11 09:48:34 +08:00 第一种更容易 compose handle functions ,如果用户需要额外的逻辑的话,第二种就没办法实现了。 |
![]() | 6 huijiewei OP 感谢大家的回复。最终使用第二种方案,利用 useMergeRefs 的能力,合并 handle 也非常简单 |
![]() | 7 juneszh 2022-08-11 12:31:33 +08:00 ref |