精读React hook(十二):使用useImperativeHandle能获得什么能力
useImperativeHandle
是一个相对少用但必要的时候能让你的 React 代码更灵活的 hook,本文我们就来探讨一下useImperativeHandle
的使用方法和使用场景。
useImperativeHandle
的使用
useImperativeHandle
通常与forwardRef
一起使用,以便将 ref 传递给函数组件,用法定义如下:
const ForwardRefChildComponents = forwardRef(function ChildComponents(props, ref) {
useImperativeHandle(ref, () => {
return {
// ... your methods ...
};
}, []);
})
基础示例
想象一个简单的例子,你有一个自定义输入组件,你想为其提供一个方法来清除输入内容,但不想暴露整个组件或 DOM 节点。
const ForwardedCustomInput = forwardRef(function CustomInput(props, ref) {
const inputRef = useRef();
useImperativeHandle(ref, () => ({
clear: () => {
inputRef.current.value = '';
}
}));
return <input ref={inputRef} />;
})
现在,当你使用ForwardedCustomInput
并为其提供一个 ref 时,你可以直接调用clear
方法
function App() {
const inputRef = useRef();
return (
<div>
<ForwardedCustomInput ref={inputRef} />
<button onClick={() => inputRef.current.clear()}>Clear Input</button>
</div>
);
}
当我们点击 “Clear Input” 按钮时,输入框的内容将被清除,这种实现方式让我们没有操作 DOM 节点也能操作完成操作。
线上示例可以到👉 <我的演示站>体验。
应用场景
尽管useImperativeHandle
能让你的 React 应用变得更灵活,但你不应该为了这样的灵活而过度使用。
有一条准则可以说明何时使用useImperativeHandle
——如果使用 props 可以解决的场景都不要使用 refs,也就无需使用useImperativeHandle
。
你应该只在确实需要自定义暴露给父组件的实例值时使用useImperativeHandle
。例如以下场景:
- 滚动到节点
- 聚焦节点
- 触发动画:你可能有一个组件负责管理复杂的动画,你可以使用
useImperativeHandle
来暴露start
和stop
等控制方法。 - 选择文本
优势和局限
使用 useImperativeHandle
可以带来的好处
- 更好的封装:你可以只暴露你想让父组件访问的特定方法或属性。
- 更多的控制:你可以精确控制组件的行为,而不是依赖于状态或属性的变化。
它的局限性及潜在风险
- 过度使用:过度依赖
useImperativeHandle
可能会导致代码难以理解和维护。 - 可能引起不必要的重新渲染:如果依赖于外部变量或状态,可能会导致不必要的组件重新渲染。使用
useCallback
或useMemo
可以一定程度上减少这样的重新渲染。
结语
useImperativeHandle
提供了一种精确控制组件对外暴露的能力,有了它,开发者可以轻松实现对组件的细粒度控制和高度封装。
系列文章列表
未完待续……
转载自:https://juejin.cn/post/7279242388999372854