useRef
- useRef 返回一个可变的 ref 对象,其 current 属性被初始化为传入的参数
- 返回的对象在组件的整个生命周期内保持不变。
forwardRef
- 被 React.forwardRef 包裹的组件接受 props 和 ref 作为参数
- 可以将 ref 从父组件转到子组件的DOM上,使得父组件中可以获取子组件的DOM。
useRef 与 forwardRef 示例
// 父组件
import { useRef } from "react";
import Child from "./Child";
export default function App() {
const inputRef = useRef();
const getFocus = () => {
inputRef.current.focus();
};
return (
<div className="App">
<Child ref={inputRef} />
<button onClick={getFocus}>聚焦</button>
</div>
);
}
// 子组件
import { forwardRef } from "react";
const Child = forwardRef((props, ref) => {
return (
<div>
<span>子组件</span>
<input ref={ref} />
</div>
);
});
export default Child;
useRef 与 forwardRef 结合使用,将子组件完全保留给父组件,父组件可以进行任意操作,这样的可控性并不好。一般父组件需要啥,子组件就暴露啥,这样更好。useImperativeHandle 就可以做到。
useImperativeHandle
useImperativeHandle(ref, createHandle, [deps])
- 第一个参数为父组件传递的 ref
- 第二个参数是一个函数,返回的一个对象会自动绑定到ref上。 即子组件可以将自己内部的方法或者值通过useImperativeHandle添加到父组件中useRef定义的对象中。
- 第三个参数是函数依赖的值(可选)。若 createHandle 函数中使用到了子组件内部定义的变量,则还需要将该变量作为依赖变量成为useImperativeHandle第3个参数
- 需 useRef 和 forwardRef 共同使用
下面这个例子是上面例子的改造:
// 父组件
import { useRef } from "react";
import Child from "./Child";
export default function App() {
const inputRef = useRef();
const getFocus = () => {
inputRef.current.focus();
console.log(inputRef.current.name);
};
return (
<div className="App">
<Child ref={inputRef} />
<button onClick={getFocus}>点击</button>
</div>
);
}
// 子组件
import { forwardRef, useImperativeHandle, useRef } from "react";
const Child = forwardRef((props, ref) => {
const inputRef = useRef(null);
useImperativeHandle(ref, () => ({
name: "我是子组件",
focus: () => {
inputRef.current.focus();
}
}));
return (
<div>
<span>子组件</span>
<input ref={inputRef} />
</div>
);
});
export default Child;