React 函数式组件的 Ref 和子组件访问(useImperativeHandle)
作者:互联网
对于 React 中需要强制修改子组件的情况,React 提供了 Refs 这种解决办法,使得我们可以操作底层 DOM 元素或者自定的 class 组件实例。除此之外,文档(v17.0.1)对函数式组件另有描述:
不能在函数式组件上使用ref属性,因为他们没有实例
。
在函数式组件和 Hooks 大面积普及的现在,这个特性没有完全对标 class 组件,令人难以置信。经过一阵探索,发现确实是有对应的解决方案的:
useImperativeHandle
结合 React.forwardRef , useImperativeHandle 文档 应该就能明白是如何使用的。
简而言之就是可以在函数式组件上使用 ref,通过useImperativeHandle
这个hook
可以指定暴露给父组件的值和函数。
案例:
修改子组件Counter
中的值, 达到重置count
的目的:
export default function App() {
return (
<div>
<button>reset</button>
<Counter />
</div>
);
}
/** -------------------------------------- */
function Counter() {
const [count, setCount] = useState(0);
function increment() {
setCount(count + 1);
}
return (
<div>
<hr />
<span>{count}</span>
<button onClick={increment}>+1</button>
</div>
);
}
对于这个案例,将
count
这个state往上提一层到 App 组件中是比较合适的,但是在这里重点讨论操作子组件。
使用useImperativeHandle
,修改代码:
export default function App() {
const counterRef = useRef();
function reset() {
counterRef.current?.resetCount();
}
return (
<div style={{ padding: 10 }}>
<button onClick={reset}>reset</button>
<MyCounter ref={counterRef} />
</div>
);
}
/** -------------------------------------- */
function Counter(props, ref) {
const [count, setCount] = useState(0);
useImperativeHandle(ref, () => ({
resetCount: resetCount,
}));
function resetCount() {
setCount(0);
}
function increment() {
setCount(count + 1);
}
return (
<div>
<hr />
<span>{count}</span>
<button onClick={increment}>+1</button>
</div>
);
}
const MyCounter = React.forwardRef(Counter);
重点是useImperativeHandle
中定义了resetCount
,以及使用React.forward
获取 ref,在App
组件中为MyCounter
中定义ref
属性,然后就可以在外部父组件中使用通过ref
调用子组件的resetCount
方法。
到这里,实际上已经达到了和class
中ref
对等的效果。通过给函数式组件设置 ref 并调用组件的方法是可行的,useImperativeHandle
除了添加方法,也可以指定值暴露出去。
函数式组件的Ref是什么
将 ref 设置到 HTML 元素上,获取的是对应的DOM元素,如span:
设置到 class 组件上,获取的是 class 组件实例:
设置到函数式组件上的时候,获取的是一个包含可变值或函数的对象,如上例的 Counter 组件:
React.createRef
和 useRef
都是创建了一个包含current
属性的对象,绑定ref
时,对应的属性和函数都在current
对应的对象中。
查看对应的TypeScript
类型,React.createRef
创建的是React.RefObject
类型,是只读的。
而useRef
创建的是React.MutableRefObject
,是可读写的。可以保存任何可变的值,使用方式类似于class
组件的this
实例变量。(又是和class
组件对标的一个点)
文档描述 useRef 为可以在其
.current
属性中保存一个可变值的“盒子”。
所以实际上应该是,对函数式组件可设置 ref,且设置的 ref 是一个可变对象,存放组件的变量,也能通过useImperativeHandle
访问函数式组件的方法。 但是并不能像将 ref 设置到 class 组件和 DOM 元素上那样获取到对应的实例。
标签:function,count,useImperativeHandle,React,组件,ref 来源: https://www.cnblogs.com/xuxiaowei/p/14323745.html