阅读时间约为 8 分钟。
文末有福利哦~
昨天我们讨论了 React 中的 useRef
钩子函数: {文章链接} ,其中的一个场景是在函数组件中使用 useRef
来创建一个 ref
对象,然后将其绑定到一个元素上,从而获取该元素的引用以便对引用的元素做出各种操作。而当我们想要在父组件中访问子组件的引用时该怎么做呢?
答案是通过 React 的 forwardRef
API 来实现。
初识 forwardRef API
forwardRef
API 允许我们从父组件向子组件传递一个 ref
,从而让父组件能够访问子组件的 DOM 节点或实例。语法如下:
const SomeComponent = forwardRef(render);
通常来说,我们可以通过回调函数的方式来让父组件访问到子组件,也就是通过 props 将回调函数传递给子组件,以便在父组件中访问子组件中的 DOM 节点或实例。但在某些情况下,这种方式不够方便或灵活。而 forwardRef
则可以提供一种更为灵活的方法来解决这个问题。
当我们使用 forwardRef
将子组件包装起来时,我们可以通过 forwardRef
的第二个参数 ref
访问子组件。然后,将该 ref
传递给子组件中需要引用的元素或组件,从而使父组件能够访问子组件的实例或 DOM 节点。这使得 forwardRef
成为一种非常强大和灵活的工具,可以帮助我们轻松地访问和操作子组件中的元素或组件。
如何使用 forwardRef API
要使用 forwardRef
来访问子组件的 DOM 节点或实例,以下两个步骤缺一不可:
通过
forwardRef
包装子组件
在父组件中,将ref
参数传递给通过forwardRef
函数包装子组件这样父组件:const ChildComponent = forwardRef((props, ref) => { // 子组件代码 });
forwardRef
包裹的是一个函数式组件,函数第二个参数就是父组件传递过来的ref
对象。可以使用我们上一篇文章中探讨的 useRef 方法在父组件中创建一个ref
对象。在子组件中访问
ref
对象
在子组件中,将ref
对象绑定到需要访问的元素或组件上,从而使父组件能够访问该 DOM 元素或组件的实例。const ChildComponent = forwardRef((props, ref) => { return ( <div> {/* ref 对象被绑定在了 input 元素上 */} <input type="text" ref={ref} /> </div> ); });
我们将
ref
对象绑定到input
元素上,这样在父组件中就可以使用ref.current
来访问input
元素的实例。const ParentComponent = () => { const inputRef = useRef(null); const handleClick = () => { inputRef.current.focus(); // 使子组件 input 元素聚焦 }; // 渲染子组件,并将 ref 对象传递给它 return ( <div> <ChildComponent ref={inputRef} /> <button onClick={handleClick}>Focus input</button> </div> ); };
我们使用
useRef
方法来创建一个ref
对象inputRef
,并将其传递给子组件ChildComponent
。然后,在handleClick
函数中,我们使用inputRef.current.focus()
方法来使input
元素聚焦。
结合 useRef
方法,我们通过上面的两个步骤便能方便的访问到子组件中被绑定了 ref
对象的 DOM 元素了。
除此之外,我们在编写在高阶组件(Higher-Order Component,HOC)时也会经常用到 forwardRef
API。高阶组件是一个函数,它接收一个组件作为参数,并返回一个新的组件。forwardRef
可以帮助我们确保 ref
被正确地传递到被包装的组件中。
// 高阶组件 withWrapper 接收一个组件 WrappedComponent 作为参数,并返回一个由 forwardRef 包裹的新组件
function withWrapper(WrappedComponent) {
return forwardRef((props, ref) => {
return (
<div ref={ref}>
<WrappedComponent {...props} />
</div>
);
});
}
const ChildComponent = ({ text }) => {
return <div>{text}</div>;
};
const ParentComponent = () => {
const wrapperRef = useRef(null);
useEffect(() => {
console.log(wrapperRef.current); // <div>...</div>
}, []);
// 将子组件 ChildComponent 作为参数传递给高阶函数 withWrapper,并返回一个新组建 WrappedChildComponent
const WrappedChildComponent = withWrapper(ChildComponent);
// 渲染由高阶组件返回的新组件,并将 ref 对象 wrapperRef 作为一个属性传递给这个新组建 WrappedChildComponent
return (
<div>
<WrappedChildComponent ref={wrapperRef} text="Hello, world!" />
</div>
);
};
在上面的示例中,我们定义了一个名为 withWrapper
的高阶组件,该函数接收一个组件作为参数,并返回一个新的组件。这个新的组件将被包裹在一个 div 元素中,并将这个 div
元素的引用作为 ref
传递给被包装的组件。
在 ParentComponent
父组件中,我们使用 withWrapper
高阶函数来创建一个新的组件 WrappedChildComponent
,并将其引用传递给 wrapperRef
。这样,当 ParentComponent
渲染时,我们就可以在 useEffect
钩子函数中通过 wrapperRef
对象访问高阶函数中的 div
元素,从而执行一些操作。
应用场景
结合上面的示例我们不难发现,forwardRef
API 通常适用于以下两个场景:
- 通过
ref
对象访问子组件的 DOM 节点; - 在高阶组件中使用
forwardRef
。
其实还可以在组件库中使用,比如我们熟知的 antd
中的 Modal
组件就提供了 ref
的访问能力。
由此我们知道,通过使用 forwardRef
,我们可以轻松地将 ref
对象传递到子组件中,从而可以访问子组件的实例或者 DOM 节点,执行一些操作。
总结
简单回顾一下本文关于 forwardRef
API 在 React 中的作用和使用方法:
forwardRef
可以用来访问子组件中的 DOM 节点或实例;- 在编写高阶组件时,
forwardRef
能确保ref
对象被正确的传递到被包装的组件中。
React 中的 forwardRef
是一个非常重要的 API,因为它能帮我们处理一些特殊场景,比如文中提到的访问子组件的 DOM 节点或者用于编写高阶组件。通过使用 forwardRef
API,我们能更加方便的操作 React 组件,还能大大提高我们的开发效率。因此,掌握 React 中的 forwardRef
是非常非常必要的。如果不了解这个 API,比如要实现访问子组件 DOM 节点的需求,通过回调函数等方式实现的话将会非常之繁琐。
所以,你学会 forwardRef
了吗?学会的小伙伴在下面留言扣个 1 ~
福利来啦~ 关注微信公众号 码上花甲 后台回复 JavaScript权威指南 可获取这本书的电子版哦,电子书是最新的第 6 版。书名全称为《JavaScript权威指南(原书第6版)》,作者是大名鼎鼎的David Flanagan,书的内容就不用咱多做介绍了吧~ 懂的都懂、前端攻城狮人手一份、
期待你学有所成哦 😘