我想实现可以添加到应用程序任何部分的特定鼠标悬停行为。
我希望这不会创建额外的嵌套标记,如果可以避免的话。
在 Angular 中,这可以通过类似<some-component myBehavior="…">
来实现,我在其中实现了一个myBehavior
属性指令。
在带有功能组件的 React 中,实现这一目标的主流方法似乎是使用 hooks,我可以将 ref 与组件中的顶级元素相关联,并将该 ref 传递给我的钩子(useMyBehavior(mainElRef, …)
(。
虽然这似乎是有道理的,但不幸的是,我必须对想要这种行为的每个组件(可能很多(执行此操作。此外,如果顶级元素是另一个自定义组件,则获取"具体"底层DOM元素(div
,span
等(的引用可能涉及更多的逻辑。
所有这些都是可行的,并且比额外的嵌套标记(这对现有样式有很多影响(要好,但如果可能的话,我宁愿避免大量的工作和额外的逻辑。毕竟,我需要知道的钩子只是鼠标指针何时进入当前组件元素的边界框。
因此问题来了:让我的钩子聪明地掌握作为当前组件的顶级包装器而不必向其传递 ref的具体DOM 元素的最可行方法是什么?
不幸的是,没有捷径可以将ref
获取到组件的顶级 DOM 元素。React Hook 并不"知道"它们在哪个组件中渲染。添加这个功能会破坏 React 的原则之一:
React 组件隐藏了它们的实现细节,包括它们的渲染输出。
但是,您可以在钩子中创建并返回ref
,因此不需要传递ref
。
function useMyBehavior() {
const ref = useRef();
useEffect(() => {
function onMouseover(e) {
// do whatever with ref.current
}
ref.current.addEventListener("mouseover", onMouseover);
return () => ref.current.removeEventListener("mouseover", onMouseover);
}, [ref.current]);
return ref;
}
function Component() {
const ref = useMyBehavior();
return (
<NestedComponent ref={ref} prop={"prop"} />
);
}
const NestedComponent = React.forwardRef((props, ref) => {
return (
<div ref={ref}>
{props.prop}
</div>
);
}
只要自定义组件使用React.forwardRef
将 ref 向下转发到 DOM 元素,钩子就会起作用。请参阅有关转发引用的文档部分。