Skip to content
js
import { Ref, useState, useRef } from 'react'

export function useHover<T extends HTMLElement>(): [Ref<T>, boolean] {
  // your code here
  const [hovering, setHovering] = useState(false);
  const custormRef = useRef<T>();

  const handleMouseEnter = () => {
    setHovering(true);
  }
  const handleMouseLeave = () => {
    setHovering(false);
  }
const handler = (node: T) => {
// remove previous node event
if(custormRef.current?.nodeType === Node.ELEMENT_NODE) {
  custormRef.current.removeEventListener("mouseenter", handleMouseEnter)
  custormRef.current.removeEventListener("mouseleaver", handleMouseLeave)
}


  if(node?.nodeType === Node.ELEMENT_NODE) {
    node.addEventListener("mouseenter", handleMouseEnter)
    node.addEventListener("mouseleave", handleMouseLeave)
    custormRef.current = node;
  }
}

  return [
    handler,
    hovering
  ]
}

实现参考的是 https://github.com/uidotdev/usehooks/blob/main/index.js useHover 的实现 利用 ref 回调,对特定的元素,进行事件绑定 要注意的一点是,在对元素进行事件绑定的时候,要移除之前存在的绑定。

js
  function App() {
    const [ref, isHovered] = useHover<HTMLDivElement>()
    const [refTarget, setRefTarget] = useState<number>(0)
    return (
      <div>
        <p>{isHovered ? 'hovered' : 'not hovered'}</p>
        <button
          data-testid="change-ref-target-button"
          onClick={() => {
            setRefTarget((target) => (target + 1) % 2)
          }}
        >
          toggle ref target
        </button>
        <div ref={refTarget === 0 ? ref : null} data-testid="hover-target0">
          target 0
        </div>
        <div ref={refTarget === 1 ? ref : null} data-testid="hover-target1">
          target 1
        </div>
      </div>
    )
  }