当前位置: 首页 > news >正文

学习React-15-useImperativeHandle

useImperativeHandle

useImperativeHandle 是 React 的一个 Hook,用于自定义向父组件暴露的 ref 句柄。通常与 forwardRef 结合使用,允许子组件控制父组件通过 ref 访问的属性和方法。

基本语法

useImperativeHandle(ref, createHandle, dependencies?)
  • ref:通过 forwardRef 传递的 ref 对象。
  • createHandle:一个函数,返回需要暴露给父组件的对象。
  • dependencies(可选):依赖项数组,类似 useEffect 的依赖项,用于控制何时重新计算 createHandle

使用场景

  1. 限制暴露的属性和方法:默认情况下,通过 ref 可以访问子组件的全部实例。使用 useImperativeHandle 可以只暴露特定的方法或属性。
  2. 封装第三方库:在包装第三方库时,可能需要隐藏底层实现,只暴露部分接口。
  3. 优化性能:避免父组件直接操作子组件的 DOM 或实例,减少不必要的渲染或副作用。

小栗子

import React, { useState, useRef, forwardRef, useImperativeHandle } from 'react'interface ChildRef {name: string,count: number,add: () => void,minus: () => void
}// React 18版本的用法
// const Child = React.forwardRef<ChildRef>((props, ref) => {
// 相对于React版本,19版本将ref放在了props中
const Child = ({ref}: {ref:React.Ref<ChildRef>}) => {const [count, setCount] = useState(0)const add = () => {setCount(count + 1)}const minus = () => {setCount(count - 1)}useImperativeHandle(ref, () => {return {name: 'child',count,add,minus}})return (<div><div>这是子组件</div><div>count: {count}</div><button onClick={add}>+</button><button onClick={minus}>-</button></div>)
})export const App = () => {const childRef = useRef<ChildRef>(null)return (<div><h1>我是父组件</h1><button onClick={() => childRef.current?.add()}>操作子组件 +</button><button onClick={() => childRef.current?.minus()}>操作子组件 -</button><br /><button onClick={() => console.log(childRef.current)}>获取子组件</button><Child ref={childRef} /></div>)
}
export default App

实际案例

需求: 利用父子组件实现表单的验证

父组件

import React, { useState, useRef, forwardRef, useImperativeHandle, useEffect } from 'react'
import TextFrom from './textFrom'
import './index.css'interface FromProps {handleSubmit: (e: React.FormEvent) => voidhandleReset: () => voidcheckForm: () => voidfromData: {text: string,password: string,number: string}
}export const App = () => {const chlidFormRef = useRef<FromProps>(null)const [formData, setFormData] = useState({ text: '', password: '' });const getFormData = () => {if (chlidFormRef.current) {// 触发表单提交// 这里我们直接获取表单数据并更新状态setFormData({text: chlidFormRef.current.fromData.text,password: chlidFormRef.current.fromData.password});}};return (<div><div className='login_main'><div className="login-left"><h1>登陆人</h1><div>用户: {formData.text}</div><div>密码: {formData.password}</div></div><div className="login-right"><TextFrom ref={chlidFormRef} /><div className="form-buttons"><button type="button" className="submit-button" onClick={chlidFormRef.current?.handleSubmit}>登录</button><button type="button" onClick={chlidFormRef.current?.handleReset} className="reset-button">重置</button><button className="submit-button" onClick={() => chlidFormRef.current?.checkForm()}>检查表单</button><button className="submit-button" onClick={getFormData}>获取数据</button></div></div></div></div>)
}
export default App

子组件

import React, { useState, useImperativeHandle, useEffect } from 'react'interface FromProps {handleSubmit: (e: React.FormEvent) => voidhandleReset: () => voidcheckForm: () => voidfromData: {text: string,password: string,number: string}
}
const From = ({ ref }: { ref: React.Ref<FromProps> }) => {const [formData, setFromData] = useState({text: '',password: '',number: ''})const [isSubmit, setIsSubmit] = useState(false)type Action = 'text' | 'password' | 'number'// 更新数据const HandleState = (action: Action, value: string) => {switch (action) {case 'text':setFromData((preState) => ({ ...preState, text: value }))break;case 'password':setFromData((preState) => ({ ...preState, password: value }))break;case 'number':setFromData((preState) => ({ ...preState, number: value }))break;}}useEffect(() => {console.log(formData);}, [formData])const checkForm = () => {if (formData.text == '') {alert('名称不能为空');return}if (formData.password == '') {alert('密码不能为空');return}if (formData.number == '') {alert('验证码不能为空');return}setIsSubmit(true)}const handleSubmit = (e: React.FormEvent) => {// 阻止浏览器默认的提交行为e.preventDefault();if (!isSubmit) {alert('请先检查表单');return}console.log(formData);// 登录成功后可以在这里添加回调或其他逻辑}// 重置输入const handleReset = () => {setFromData({text: '',password: '',number: ''})}// 暴露给父组件useImperativeHandle(ref, () => {return {handleSubmit,checkForm,handleReset,fromData: formData}})return (<div className="form-container"><h2 className="form-title">用户登录</h2><form onSubmit={handleSubmit} className="login-form"><div className="form-group"><label htmlFor="text">用户名</label><inputtype="text"id="text"value={formData.text}onChange={(e) => HandleState('text', e.target.value)}className="form-input"placeholder="请输入用户名"/></div><div className="form-group"><label htmlFor="password">密码</label><inputtype="password"id="password"value={formData.password}onChange={(e) => HandleState('password', e.target.value)}className="form-input"placeholder="请输入密码"/></div><div className="form-group"><label htmlFor="number">验证码</label><inputtype="text"id="number"value={formData.number}onChange={(e) => HandleState('number', e.target.value)}className="form-input"placeholder="请输入验证码"/></div></form></div>)
}export default From

注意事项

  1. 避免滥用:React 推荐以 props 为主,ref 为辅。过度使用 useImperativeHandle 可能导致代码难以维护。
  2. 依赖项优化:如果 createHandle 依赖外部变量,需在依赖项数组中声明,避免过期闭包问题。
  3. forwardRef 结合:必须使用 forwardRef 包装子组件,否则无法传递 ref。

对比其他方案

  • 直接传递 ref:父组件可以访问子组件的全部实例,但可能破坏封装性。
  • 回调 ref:通过回调函数传递 ref,灵活性高,但逻辑可能分散。
  • useImperativeHandle:提供更精细的控制,适合需要隐藏实现细节的场景。
http://www.dtcms.com/a/398356.html

相关文章:

  • 响应式网站案列小学生做电子小报的网站
  • 【AskAI系列课程】:P4.将AI助手集成到Astro网站前端
  • 自注意力机制(Self-Attention)简介
  • App 代上架全流程解析 iOS 应用代上架服务、苹果应用发布步骤、ipa 文件上传与 App Store 审核经验
  • 学习日报 20250921|MQ (Kafka)面试深度复盘
  • 趣味学Solana(启航)
  • 期权末日论效应怎么来的?
  • iOS 混淆与反调试反 Hook 实战,运行时防护、注入检测与安全加固流程
  • 建设工程管理网站邹平建设网站
  • wordpress英文下主题怎么换苏州seo专家教优化网站结构
  • 《灼灼韶华》还原民国上海滩,虎鲸文娱虚拟拍摄让创作突破时空束缚
  • Redo Log 与 Crash Recovery:MySQL 事务持久化的核心技术
  • 金乡网站建设公司云南企业网站
  • 设计模式(C++)详解——职责链模式 (Chain of Responsibility)(1)
  • 酒店网站免费建设国际新闻今天最新
  • 企业产品网络安全日志9月23日-WAF应急
  • 嵌入式硬件工程师:绝缘栅型场效应管
  • HTTPS 请求抓包实战,从请求捕获到解密分析的逐步流程与工具组合(https 请求抓包、iOS 真机、SSL Pinning 排查)
  • 怎么学习cuda?
  • iOS 开发指南全解析 从入门到应用上架、Xcode 使用教程、ipa 打包上传与 App Store 审核实战经验
  • iOS 26 帧率测试实战指南,Liquid Glass 动画性能、滚动滑动帧率对比、旧机型流畅性与 uni-app 优化策略
  • 在网站上签失业保险怎样做网站对公司的重要性
  • php网站模板 php网站源码 PHP源码网
  • 万能PDF工具箱(PDF Candy)安装教程
  • 两款功能强大的密码学工具箱
  • umijs 4.0学习 - 路由
  • 【Java】P7 Java数组完全指南:从基础到进阶
  • PTZ相机AI相关的知识体系
  • Python 2025:新型解释器与性能优化实战
  • go 持续集成、持续部署之gitlab流水线+docker-compose踩坑之旅