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 ...
随机推荐
- Flash图解线程池 | 阿里巴巴面试官希望问的线程池到底是什么?
前言 前几天小强去阿里巴巴面试Java岗,止步于二面. 他和我诉苦自己被虐的多惨多惨,特别是深挖线程和线程池的时候,居然被问到不知道如何作答. 对于他的遭遇,结合他过了一面的那个嘚瑟样,我深表同情(加 ...
- JavaScript(二)——在 V8 引擎中书写最优代码
概述 一个 JavaScript 引擎就是一个程序或者一个解释程序,它运行 JavaScript 代码.一个 JavaScript 引擎可以用标准解释程序或者即时编译器来实现,即时编译器即以某种形式把 ...
- Flink-v1.12官方网站翻译-P023-The Broadcast State Pattern
广播状态模式 在本节中,您将了解如何在实践中使用广播状态.请参考状态流处理,了解状态流处理背后的概念. 提供的API 为了展示所提供的API,我们将在介绍它们的全部功能之前先举一个例子.作为我们的运行 ...
- Angular写一个Form组件-TagInput
前端开发少不了和表单打交道; Angular中, 提供了强大的表单的支持, 响应式表单(Reactive Form) 和 模板驱动的表单(Template-driven Form) 的双向数据流给我们 ...
- C# 如何复制(拷贝)Label控件上的文本【新方法】
Label控件在目前是无法直接调用成员函数来复制其文本内容.其实网络上有很多热心程序员网民解答过这个问题,百度上也可以搜索到,不过大多数人建议使用 TextBox 并把边框调整为不可见(运行时文本框看 ...
- AtCoder Beginner Contest 176
比赛链接:https://atcoder.jp/contests/abc176 A - Takoyaki #include <bits/stdc++.h> using namespace ...
- Codeforces Round #622 (Div. 2) C2. Skyscrapers (hard version)(单调栈,递推)
Codeforces Round #622 (Div. 2) C2. Skyscrapers (hard version) 题意: 你是一名建筑工程师,现给出 n 幢建筑的预计建设高度,你想建成峰状, ...
- Codeforces Round #692 (Div. 2, based on Technocup 2021 Elimination Round 3) C. Peaceful Rooks (思维,dsu找环)
题意:一个棋盘上有一些"车",现在要让这些"车"跑到左倾斜的对角线上,每次可以移动一个棋子,但是棋盘的任意时刻都不能出现一个"车"能吃另一个 ...
- python+selenium+bs4爬取百度文库内文字 && selenium 元素可以定位到,但是无法点击问题 && pycharm多行缩进、左移
先说一下可能用到的一些python知识 一.python中使用的是unicode编码, 而日常文本使用各类编码如:gbk utf-8 等等所以使用python进行文字读写操作时候经常会出现各种错误, ...
- P1541 乌龟棋(DP)
题目背景 小明过生日的时候,爸爸送给他一副乌龟棋当作礼物. 题目描述 乌龟棋的棋盘是一行NNN个格子,每个格子上一个分数(非负整数).棋盘第1格是唯一的起点,第NNN格是终点,游戏要求玩家控制一个乌龟 ...