useRef
、useImperativeHandle
和 forwardRef
是 React 中用于处理 引用(Ref) 的三个重要 API。它们通常用于直接访问 DOM 元素或子组件的实例。以下是它们的详细说明和用法:
1. useRef
useRef
是一个 Hook,用于创建一个可变的引用对象。它的主要用途包括:
-
访问 DOM 元素。
-
存储可变值(类似于类组件的实例变量)。
1.1 基本用法
import React, { useRef } from 'react'; function MyComponent() { const inputRef = useRef(null); const focusInput = () => { inputRef.current.focus(); }; return ( <div> <input type="text" ref={inputRef} /> <button onClick={focusInput}>Focus Input</button> </div> ); }
1.2 特点
-
useRef
返回的对象在组件的整个生命周期内保持不变。 -
修改
ref.current
不会触发组件的重新渲染。
2. forwardRef
forwardRef
用于将 ref
从父组件传递到子组件。通常用于封装第三方组件或高阶组件。
2.1 基本用法
import React, { useRef, forwardRef } from 'react'; // 子组件 const ChildComponent = forwardRef((props, ref) => { return <input type="text" ref={ref} />; }); // 父组件 function ParentComponent() { const inputRef = useRef(null); const focusInput = () => { inputRef.current.focus(); }; return ( <div> <ChildComponent ref={inputRef} /> <button onClick={focusInput}>Focus Input</button> </div> ); }
2.2 特点
-
forwardRef
允许父组件直接访问子组件的 DOM 元素或实例。 -
适用于封装需要暴露
ref
的自定义组件。
3.1 基本用法
import React, { useRef, forwardRef, useImperativeHandle } from 'react'; // 子组件 const ChildComponent = forwardRef((props, ref) => { const inputRef = useRef(null); // 自定义暴露给父组件的 ref 值 useImperativeHandle(ref, () => ({ focus: () => { inputRef.current.focus(); }, getValue: () => { return inputRef.current.value; }, })); return <input type="text" ref={inputRef} />; }); // 父组件 function ParentComponent() { const childRef = useRef(null); const handleClick = () => { childRef.current.focus(); // 调用子组件暴露的方法 console.log('Input Value:', childRef.current.getValue()); // 获取输入框的值 }; return ( <div> <ChildComponent ref={childRef} /> <button onClick={handleClick}>Focus Input and Get Value</button> </div> ); }
4. 三者的结合使用
useRef
、forwardRef
和 useImperativeHandle
通常结合使用,以实现更灵活的 ref
管理。
示例:封装一个可控制的输入框组件
import React, { useRef, forwardRef, useImperativeHandle } from 'react'; // 子组件 const ControlledInput = forwardRef((props, ref) => { const inputRef = useRef(null); useImperativeHandle(ref, () => ({ focus: () => { inputRef.current.focus(); }, clear: () => { inputRef.current.value = ''; }, })); return <input type="text" ref={inputRef} />; }); // 父组件 function ParentComponent() { const inputRef = useRef(null); const handleFocus = () => { inputRef.current.focus(); }; const handleClear = () => { inputRef.current.clear(); }; return ( <div> <ControlledInput ref={inputRef} /> <button onClick={handleFocus}>Focus Input</button> <button onClick={handleClear}>Clear Input</button> </div> ); }
API | 用途 |
---|---|
useRef | 创建可变引用,用于访问 DOM 元素或存储可变值。 |
forwardRef | 将 ref 从父组件传递到子组件,适用于封装需要暴露 ref 的组件。 |
useImperativeHandle | 自定义暴露给父组件的 ref 值,限制父组件对子组件的访问权限。 |
通过合理使用这三个 API,可以实现更灵活的 ref
管理,提升组件的可复用性和可维护性。