🎯 元素目标(ElementTarget)

ElementTarget 是一个联合类型,表示 @shined/react-use 中可以被定位(targeting)的各种元素类型。

简而言之

  • 在 React 中访问元素进行点击、悬停等操作是非常常见且合理的。
  • 传统的使用 Ref 或 DOM 查询的方法,在服务器端渲染(SSR)环境中会遇到挑战。
  • 为了提升开发者体验(DX)同时支持 SSR,我们引入了 useTargetElement
  • 它通过抹平不同的元素访问的方式,简化了定位元素的过程,确保了开发体验的一致性。

如果您正在寻找 ElementTarget 类型,请参考 ElementTarget Types

动机

React Hooks 经常需要访问 DOM 元素来执行如点击组件外部(useClickAway)、悬停(useHover)或滚动(useScroll)等操作。

在传统上,React 中访问 HTML 元素主要有两种方式:

  • React Ref:使用 ref={ref}Ref 附加到元素上,并在 useEffect 等地方通过 ref.current 访问它。
  • DOM 查询:直接在 useEffect 等地方使用 document 对象上的实例方法获取元素,如 querySelector
// React Ref useEffect(() => { if (ref.current) { // 对 ref.current 做一些操作 } }, []) // 直接在渲染阶段进行 DOM 查询操作 const body = document.querySelector('body') // SSR 不友好,不推荐 // 通过 DOM 查询操作 useEffect(() => { const el = document.getElementById('target') // 对 el 做一些操作 }, [])

虽然这些方法行之有效,但它们在 SSR 环境中引入了挑战,因为在渲染阶段直接访问元素或浏览器特定对象是不可能的。相反,开发者必须使用 useEffectRef 在客户端访问这些元素或对象。此外,开发者还经常希望通过传递 Ref 直接访问元素,这在许多 Hooks 和日常使用场景中是一个共同的需求。

useTargetElement

为了解决这些问题,我们创建了 useTargetElement Hook,它简化了获取目标元素的过程。这个 Hook 返回一个包含目标元素的 React Ref:

const targetRef = useTargetElement(elementTarget)

它可以接受一个 Getter 函数作为输入,以避免 SSR 相关的错误,并且还支持包含元素的 Ref,以增强开发体验(DX)并适应广泛的使用场景。

这个 Hook 已经服务于许多 @shined/react-use 的核心功能,例如 useClickAwayuseHoveruseScroll 等等,它代表了需要在其 Hooks 内访问元素的开发者的最佳实践。

ElementTarget 类型

提示

"🚥" 前缀表示可以是 Getter 函数,这在 SSR 中特别有用。"⚛️" 前缀表示可以是包含它的 Ref

  • 🚥 ⚛️ window/document:全局 window 或 document 对象。
  • 🚥 ⚛️ Element:任何 HTML 元素。
  • 🚥 ⚛️ Element Selector:一个 CSS 选择器字符串,例如 #id.class.subclasstag 等。
  • 🚥 ⚛️ null/undefined:表示无目标,简化了错误处理,同时确保了与 TypeScript 的顺畅集成。

有效示例

const ref = useRef<HTMLDivElement>(null) // <div ref={ref} /> const targetRef = useTargetElement(ref) const targetRef = useTargetElement('#my-div') const targetRef = useTargetElement('#my-div .container') const targetRef = useTargetElement(() => window) const targetRef = useTargetElement(() => document.getElementById('my-div')) // 不推荐,会引起 SSR 问题 const targetRef = useTargetElement(window) // 不推荐,会引起 SSR 问题 const targetRef = useTargetElement(document.getElementById('my-div'))