React第十八章(useImperativeHandle)

news/2024/12/12 5:27:34/

useImperativeHandle

可以在子组件内部暴露给父组件句柄,那么说人话就是,父组件可以调用子组件的方法,或者访问子组件的属性。
如果你学过Vue,就类似于Vue的defineExpose

用法

useImperativeHandle(ref, ()=>{return {// 暴露给父组件的方法或属性}
}, [deps])

参数

  • ref: 父组件传递的ref对象
  • createHandle: 返回值,返回一个对象,对象的属性就是子组件暴露给父组件的方法或属性
  • deps?:[可选] 依赖项,当依赖项发生变化时,会重新调用createHandle函数,类似于useEffect的依赖项

入门案例

useRef 在18版本 和 19版本使用方式不一样

18版本

18版本需要配合forwardRef一起使用

forwardRef包装之后,会有两个参数,第一个参数是props,第二个参数是ref

我们使用的时候只需要将ref传递给useImperativeHandle即可,然后useImperativeHandle 就可以暴露子组件的方法或属性给父组件,
然后父组件就可以通过ref调用子组件的方法或访问子组件的属性

interface ChildRef {name: stringcount: numberaddCount: () => voidsubCount: () => void
}//React18.2
const Child = forwardRef<ChildRef>((_, ref) => {const [count, setCount] = useState(0)//重点useImperativeHandle(ref, () => {return {name: 'child',count,addCount: () => setCount(count + 1),subCount: () => setCount(count - 1)}})return <div><h3>我是子组件</h3><div>count:{count}</div><button onClick={() => setCount(count + 1)}>增加</button><button onClick={() => setCount(count - 1)}>减少</button></div>
})function App() {const childRef = useRef<ChildRef>(null)const showRefInfo = () => {console.log(childRef.current)}return (<div><h2>我是父组件</h2><button onClick={showRefInfo}>获取子组件信息</button><button onClick={() => childRef.current?.addCount()}>操作子组件+1</button><button onClick={() => childRef.current?.subCount()}>操作子组件-1</button><hr /><Child ref={childRef}></Child></div>);
}export default App;

19版本

  1. 19版本不需要配合forwardRef一起使用,直接使用即可,他会把Ref跟props放到一起,你会发现变得更加简单了
  2. 19版本useRef的参数改为必须传入一个参数例如useRef<ChildRef>(null)
interface ChildRef {name: stringcount: numberaddCount: () => voidsubCount: () => void
}//React19
const Child = forwardRef<ChildRef>((_, ref) => { // [!code --]
const Child = ({ ref }: { ref: React.Ref<ChildRef> }) => { // [!code ++]const [count, setCount] = useState(0)useImperativeHandle(ref, () => {return {name: 'child',count,addCount: () => setCount(count + 1),subCount: () => setCount(count - 1)}})return <div><h3>我是子组件</h3><div>count:{count}</div><button onClick={() => setCount(count + 1)}>增加</button><button onClick={() => setCount(count - 1)}>减少</button></div>
}function App() {const childRef = useRef<ChildRef>(null)const showRefInfo = () => {console.log(childRef.current)}return (<div><h2>我是父组件</h2><button onClick={showRefInfo}>获取子组件信息</button><button onClick={() => childRef.current?.addCount()}>操作子组件+1</button><button onClick={() => childRef.current?.subCount()}>操作子组件-1</button><hr /><Child ref={childRef}></Child></div>);
}export default App;

执行时机[第三个参数]

  1. 如果不传入第三个参数,那么useImperativeHandle会在组件挂载时执行一次,然后状态更新时,都会执行一次
useImperativeHandle(ref, () => {})
  1. 如果传入第三个参数,并且是一个空数组,那么useImperativeHandle会在组件挂载时执行一次,然后状态更新时,不会执行
useImperativeHandle(ref, () => {}, [])
  1. 如果传入第三个参数,并且有值,那么useImperativeHandle会在组件挂载时执行一次,然后会根据依赖项的变化,决定是否重新执行
const [count, setCount] = useState(0)
useImperativeHandle(ref, () => {}, [count])

实际案例

例如,我们封装了一个表单组件,提供了两个方法:校验和重置。使用useImperativeHandle可以将这些方法暴露给父组件,父组件便可以通过ref调用子组件的方法。

interface ChildRef {name: stringvalidate: () => string | truereset: () => void
}const Child = ({ ref }: { ref: React.Ref<ChildRef> }) => {const [form, setForm] = useState({username: '',password: '',email: ''})const validate = () => {if (!form.username) {return '用户名不能为空'}if (!form.password) {return '密码不能为空'}if (!form.email) {return '邮箱不能为空'}return true}const reset = () => {setForm({username: '',password: '',email: ''})}useImperativeHandle(ref, () => {return {name: 'child',validate: validate,reset: reset}})return <div style={{ marginTop: '20px' }}><h3>我是表单组件</h3><input value={form.username} onChange={(e) => setForm({ ...form, username: e.target.value })} placeholder='请输入用户名' type="text" /><input value={form.password} onChange={(e) => setForm({ ...form, password: e.target.value })} placeholder='请输入密码' type="text" /><input value={form.email} onChange={(e) => setForm({ ...form, email: e.target.value })} placeholder='请输入邮箱' type="text" /></div>
}function App() {const childRef = useRef<ChildRef>(null)const showRefInfo = () => {console.log(childRef.current)}const submit = () => {const res = childRef.current?.validate()console.log(res)}return (<div><h2>我是父组件</h2><button onClick={showRefInfo}>获取子组件信息</button><button onClick={() => submit()}>校验子组件</button><button onClick={() => childRef.current?.reset()}>重置</button><hr /><Child ref={childRef}></Child></div>);
}export default App;

http://www.ppmy.cn/news/1554408.html

相关文章

参观华为欧洲小镇攻略

华为松山湖欧洲小镇直接造了一个城&#xff01; 我用“城”这个词 并不是为了夸张或者博人眼球 全世界没有任何一个国家或公司 建造过如此规模的办公楼 甚至园区内部自带火车站&#xff01; 它就是华为总部 松山湖小镇 位于东莞松山湖畔 是华为的研发基地总部 这里平时安保措施…

Ubuntu K8s

https://serious-lose.notion.site/Ubuntu-K8s-d8d6a978ad784c1baa2fc8c531fbce68?pvs74 2 核 2G Ubuntu 20.4 IP 172.24.53.10 kubeadmkubeletkubectl版本1.23.01.23.01.23.0 kubeadm、kubelet 和 kubectl 是 Kubernetes 生态系统中的三个重要组件 kubeadm&#xff1a; 主…

List与Set、数组与ArrayList、ArrayList与LinkedList的区别

List 与 Set 的区别&#xff1a; 项ListSet重复允许重复的对象&#xff08;多个null也可以&#xff09;不允许重复的对象&#xff08;null也只能有一个&#xff09;有序性有序的。 保持了每个元素的插入顺序。即输出顺序就是输入顺序。 有序和无序都有。 HashSet&#xff1a;无…

can协议中的网络管理

为什么需要网络管理&#xff1f; 网络管理最终要实现的是车上的ECU能够协同睡眠以及唤醒&#xff0c;也就是说网络管理最重要的一点是要保证车上的ECU能够协同唤醒和休眠。那么假如车上的ECU都处于睡眠模式&#xff0c;网络上都没有报文&#xff0c;你咋实现唤醒呢&#xff0c;…

前端流式播放TTS语音:技术细节与实现

摘要 本文将介绍如何在前端实现流式播放文本到语音&#xff08;TTS&#xff09;的语音&#xff0c;并加入确保语音播放不重叠的改进方案。我们将探讨使用Web Audio API和WebSocket进行实时语音播放的技术细节&#xff0c;并提供相应的代码示例。 一、引言 在之前的讨论中&am…

基于单片机指纹识别电子寄存柜设计

摘要: 触摸屏信息显示、电控锁继电器控制、计算机终端管理控制等部分。相比于条码式寄存柜,具有操作简单,维护方便,性能可靠等诸多优 本文研究一种基于单片机的指纹识别电子寄存柜控制系统。主控芯片采用 STC12C5A60S2 增强型单片机,系统包括指纹识别、LCD点。此外,设计…

AndroidStudio-常见界面控件

一、Button package com.example.review01import androidx.appcompat.app.AppCompatActivity import android.os.Bundle import android.widget.Button import android.widget.TextViewclass Review01Activity : AppCompatActivity() {override fun onCreate(savedInstanceStat…

顶会新宠!KAN-LSTM完美融合新方案

2024深度学习发论文&模型涨点之——KANLSTM KAN-LSTM混合预测模型是一种结合了自注意力机制&#xff08;KAN, Key-attention network&#xff09;和长短时记忆网络&#xff08;LSTM&#xff09;的深度学习模型&#xff0c;主要用于序列数据的预测任务&#xff0c;如时间序…