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

React第十八章(useImperativeHandle)

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: string
   count: number
   addCount: () => void
   subCount: () => 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: string
   count: number
   addCount: () => void
   subCount: () => 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: string
   validate: () => string | true
   reset: () => 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.kler.cn/a/429870.html

相关文章:

  • Jaeger UI使用、采集应用API排除特定路径
  • 《新闻大厦抢先版》V0.18.105+Dlcs官方学习版
  • 分布式一致性CAP与BASE理论、分布式一致性协议和算法——2PC、3PC 和 Paxos算法
  • node-sass@4.14.1报错的最终解决方案分享
  • 【AniGS】论文阅读
  • 系统思考—因果关系
  • 学在西电录播课使用python下载,通过解析m3u8协议、多线程下载ts视频块以及ffmpeg合并
  • Spring:自定义的bean对象
  • 普通算法——埃氏筛
  • 基于单片机的汽车雨刷器装置
  • 酷柚易汛生产管理系统PHP+Uniapp
  • Excel VBA学习系列汇总20241205
  • 使用paho.mqtt.cpp库实现ssl/tls加密通信
  • NanoLog起步笔记-6-StaticLogInfo
  • 攻防世界 - Web - Level 1 | file_include
  • springboot的restTemplate发起get请求参数到服务端无法被解析,curl或postman可以正常调用的url。
  • 【JavaWeb后端学习笔记】Spring事务管理
  • ISO45001职业健康安全管理体系涵盖了丰富的内容
  • 【计网笔记】习题
  • 调度系统:使用 Apache Airflow 管理和调度 Couchbase SQL 脚本的实际例子
  • C++ 游戏开发与小程序:跨平台开发与智能化游戏体验的结合
  • SpringBoot | 拦截器 | 统一数据返回格式 | 统一异常处理 | 适配器模式
  • 链式设计模式:装饰模式,职责链模式
  • 一根网线如何用软路由给手机、电脑分配设置不同IP
  • 从watch、watchEffect、useEffect原理到vue、react响应原理
  • keepalived 各模式设置