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 元素上那样获取到对应的实例。
React 函数式组件的 Ref 和子组件访问(useImperativeHandle)的更多相关文章
- uni-app 父组件引用子组件时怎么调用子组件的方法
1.写一个简单的子组件main/index.vue: <template> <view> </view> </template> <script& ...
- Vue 父组件主动获取子组件的值,子组件主动获取父组件的值
父组件主动获取子组件的值 1. 在调用子组件的时候定义一个ref-> ref="header"2. 在父组件中通过this.$refs.header.属性,调用子组件的属性, ...
- Vue2.x中的父组件数据传递至子组件
父组件结构 template <template> <div> <v-girl-group :girls="aGirls"></v-gir ...
- vue 高级属性父组件provide向子组件发送数据,子组件通过inject接收数据
以前父组件向子组件中传值是通过props传值,子组件不能更改父组件中的值,但是可以通过从父组件中获取的值定义给自己的data值,这里父组件可以通过provide向子组件传递自己组件中的data值,子组 ...
- vue 父组件传递数据给子组件
父组件 <body> <div id="app"> <child v-bind:data = "test"></chi ...
- vue组件中的样式属性:scoped,解决在父组件中无法修改子组件样式问题
Scoped CSS规范是Web组件产生不污染其他组件,也不被其他组件污染的CSS规范. vue组件中的style标签标有scoped属性时表明style里的css样式只适用于当前组件元素,它是通过使 ...
- Vue : props 使用细节(父组件传递数据给子组件)
props使用细节 在Vue.js中我们可以使用 props 实现父组件传递数据给子组件,下面我们总结一下props的使用细节 1.基础类型检查 2.必填数据 3.默认值 4.自定义验证函数 其中每一 ...
- vue中父组件传数据给子组件
父组件: <template> <parent> <child :list="list"></child> //在这里绑定list对 ...
- vue 父组件数据修改,子组件数据未修改
页面: 父组件 <myfeedback></myfeedback> 子组件 <news></news> myfeedback.vue <te ...
随机推荐
- Flutter GetX使用---简洁的魅力!
前言 使用Bloc的时候,有一个让我至今为止十分在意的问题,无法真正的跨页面交互!在反复的查阅官方文档后,使用一个全局Bloc的方式,实现了"伪"跨页面交互,详细可查看:flutt ...
- XCTF-黑客精神
杂言 前段时间键盘坏了,电脑硬盘也坏了,买东西装系统再偷个懒放了一周左右假.期间学习巩固了一下安卓开发的知识.用了固态才知道什么叫纵享丝滑,当初就不该省这个钱. 前期工作 查壳,无.运行,点击按钮就跳 ...
- linux驴杂记
1. 命令行 vim下 的Ctrl + S ,ctrl +Q: 这个功能可以用于长时间编译的时候随时把屏幕输出停住,但是编译仍然会继续,这样就不会影响到编译时间了. S:是锁屏 q:是开屏 2. S ...
- 编程排序的一个excel-据说玩的好的,年薪50万了。只是你没在对的地方
是一个excel 下面是百度网盘分享地址; http://pan.baidu.com/s/1kTwqRfL
- jvm系列五-java内存模型初览(1)
本文转载自:再有人问你Java内存模型是什么,就把这篇文章发给他. 网上有很多关于Java内存模型的文章,在<深入理解Java虚拟机>和<Java并发编程的艺术>等书中也都有关 ...
- redis分布式锁的这些坑,我怀疑你是假的开发
摘要:用锁遇到过哪些问题? 一.白话分布式 什么是分布式,用最简单的话来说,就是为了较低单个服务器的压力,将功能分布在不同的机器上面:就比如: 本来一个程序员可以完成一个项目:需求->设计-&g ...
- unix环境高级编程第三章笔记
文件描述符 1.文件描述符的概念 对于内核而言,所有打开的文件都会用一个文件描述符来引用,打开或和创建一个新文件的时候,内核会给进程返回一个文件描述符,而当使用read write时,可以使用这个文件 ...
- 2018 ACM-ICPC 焦作区域赛 E Resistors in Parallel
Resistors in Parallel Gym - 102028E 吐槽一下,网上搜索的题解一上来都是找规律,对于我这种对数论不敏感的人来说,看这种题解太难受了,找规律不失为一种好做法,但是题解仅 ...
- AtCoder Beginner Contest 168
比赛链接:https://atcoder.jp/contests/abc168/tasks A - ∴ (Therefore) 题意 给出一个由数字组成的字符串 $s$,要求如下: 如果 $s$ 以 ...
- SQL Server 新安装启用sa用户/sa用户登录提示管道另一端无进程
安装时只用windows验证 安装完成后: 首先选中服务器(右键)->属性->安全性->服务器身份验证修改为"SQL SERVER和WINDOWS身份验证模式"其 ...