当前位置:首页 > 科技  > 软件

React高手都善于使用useImprativeHandle

来源: 责编: 时间:2024-01-19 17:27:51 184观看
导读一、useRef学习 useImperativeHandle,得从 useRef 说起。我们前面已经学习过了 useRef,它能够结合元素组件的 ref 属性帮我们拿到该元素组件对应的真实 DOM。例如,我想要拿到一个 input 元素的真实 DOM 对象,并调用 input

rSm28资讯网——每日最新资讯28at.com

一、useRef

学习 useImperativeHandle,得从 useRef 说起。我们前面已经学习过了 useRef,它能够结合元素组件的 ref 属性帮我们拿到该元素组件对应的真实 DOM。rSm28资讯网——每日最新资讯28at.com

例如,我想要拿到一个 input 元素的真实 DOM 对象,并调用 input 的 .focus() 方法,让 input 获得焦点。rSm28资讯网——每日最新资讯28at.com

import {useRef} from "react";export default function Demo() {  const inputRef = useRef<HTMLInputElement>(null);  const focusTextInput = () => {    if (inputRef.current) {      inputRef.current.focus();    }  }  return (    <>      <input type="text" ref={inputRef} />      <button onClick={focusTextInput}>        点击我让input组件获得焦点      </button>    </>  );}

每一个 React 提供的元素组件,都具备 ref 属性。在上面的章节中我们可以知道,当我们拿到了元素的原生 DOM 对象之后,就可以脱离 React 的开发思路,从而应对更多更复杂的场景。rSm28资讯网——每日最新资讯28at.com

那么问题就来了,原生组件有自己的 ref 属性,那么自定义组件呢?当然是没有的,因此我们得自己想办法处理。rSm28资讯网——每日最新资讯28at.com

二、forwardRef

forwardRef 能够在我们自定义组件时,把内部组件的 ref 属性传递给父组件。rSm28资讯网——每日最新资讯28at.com

它接受我们自定义的组件作为参数,并返回一个新的组件。新组件具备我们自定义组件的全部能力,并得到一个 ref 属性,父组件通过 useRef 获取到的内容与内部组件的 ref 完全一致。rSm28资讯网——每日最新资讯28at.com

我们来看一个案例。rSm28资讯网——每日最新资讯28at.com

现在我们要实现如下效果,当点击 Edit 按钮时,输入框自动获得焦点。rSm28资讯网——每日最新资讯28at.com

rSm28资讯网——每日最新资讯28at.com

我们知道,在 DOM 中,只要得到 input 对象,然后就可以调用 .focus() 方法来实现目标。现在我们要封装一个自定义的 MyInput 组件,他具备 input 同样的能力,同时,我们还要封装一个标题进去。rSm28资讯网——每日最新资讯28at.com

<label>Enter your name</label><input />

我们的代码如下:rSm28资讯网——每日最新资讯28at.com

import {forwardRef, LegacyRef} from 'react'type MyInputProps = React.InputHTMLAttributes<HTMLInputElement> & {  label: string}function MyInput(props: MyInputProps, ref: LegacyRef<HTMLInputElement>) {  const {label, ...other} = props  return (    <label>      {label}      <input {...other} ref={ref} />    </label>  )}export default forwardRef(MyInput)

MyInput 在声明时要传入两个参数,一个 props,一个 ref。通过展开运算符,我们能够确保 MyInput 支持 input 所有的属性。rSm28资讯网——每日最新资讯28at.com

封装好之后,我们就可以在点击实践中,通过 ref 得到的引用去调用 .focus() 达到 input 获取焦点的目标。rSm28资讯网——每日最新资讯28at.com

import { useRef } from 'react'import MyInput from './MyInput'export default function ImperativeHandle() {  const ref = useRef<any>(null)  function handleClick() {    ref.current?.focus()  }  return (    <form>      <MyInput         label='Enter your name:'         ref={ref}       />      <button type='button' onClick={handleClick}>Edit</button>    </form>  )}

三、useImperativeHandle

在实践中,很多时候,我们并不想通过 ref 去获取子组件内部的某个元素组件的真实 DOM 对象。而是希望父组件能够调用子组件内部的某些方法rSm28资讯网——每日最新资讯28at.com

但是在 React 中,又无法直接 new 一个子组件的实例,像面向对象那样通过子组件实例去调用子组件的方法。rSm28资讯网——每日最新资讯28at.com

因此,React 提供了一个 hook,useImperativeHandle,让我们能够重写子组件内部 ref 对应的引用,从而达到在父组件中,调用子组件内部方法的目的rSm28资讯网——每日最新资讯28at.com

例如,上面的 MyInput 组件,我们可以修改代码为:rSm28资讯网——每日最新资讯28at.com

import {forwardRef, useImperativeHandle, useRef} from 'react'type MyInputProps = React.InputHTMLAttributes<HTMLInputElement> & {  label: string}function MyInput(props: MyInputProps, ref: any) {  const {label, ...other} = props  const inputRef = useRef<any>(null)  useImperativeHandle(ref, () => {    return {      focus() {        inputRef.current.focus()      }    }  }, [])  return (    <label>      {label}      <input {...other} ref={inputRef} />    </label>  )}export default forwardRef(MyInput)
useImperativeHandle(  ref,   createHandle,   dependencies?)

useImperativeHandle 接收三个参数,分别是rSm28资讯网——每日最新资讯28at.com

  • ref: 组件声明时传入的 ref。
  • createHandle: 回调函数,需要返回 ref 引用的对象,我们也是在这里重写 ref 引用。
  • deps: 依赖项数组,可选。state,props 以及内部定义的其他变量都可以作为依赖项,React 内部会使用 Object.is 来对比依赖项是否发生了变化。依赖项发生变化时,createHandle 会重新执行,ref 引用会更新。如果不传入依赖项,那么每次更新 createHandle 都会重新执行。

useImperativeHandle 执行本身返回 undefined。rSm28资讯网——每日最新资讯28at.com

四、官方案例

官方文档中有这种一个案例,效果如图所示。当点击按钮时,我希望下方的 input 自动获得焦点,并切中间的滚动条滚动到最底部。rSm28资讯网——每日最新资讯28at.com

rSm28资讯网——每日最新资讯28at.com

现在,我们结合前面的知识来分析一下这个案例应该如何实现。rSm28资讯网——每日最新资讯28at.com

首先我们先进行组件拆分,将整个内容拆分为按钮部分与信息部分,信息部分主要负责信息的暂时与输入,因此页面组件大概长这样。rSm28资讯网——每日最新资讯28at.com

<>  <button>Write a comment</button>  <Post /></>

我们期望点击按钮时,信息部分的输入框自动获取焦点,信息部分的信息展示区域能滚动到最底部,因此整个页面组件的代码可以表示为如下:rSm28资讯网——每日最新资讯28at.com

import { useRef } from 'react';import Post from './Post.js';export default function Page() {  const postRef = useRef(null);  function handleClick() {    postRef.current.scrollAndFocusAddComment();  }  return (    <>      <button onClick={handleClick}>        Write a comment      </button>      <Post ref={postRef} />    </>  );}

信息部分 Post 又分为两个部分,分别是信息展示部分与信息输入部分。rSm28资讯网——每日最新资讯28at.com

此时这两个部分的 ref 要透传给 Post,并最终再次透传给页面组件。rSm28资讯网——每日最新资讯28at.com

所以信息展示部分 CommentList 组件的代码为。rSm28资讯网——每日最新资讯28at.com

import { forwardRef, useRef, useImperativeHandle } from 'react';const CommentList = forwardRef(function CommentList(props, ref) {  const divRef = useRef(null);  useImperativeHandle(ref, () => {    return {      scrollToBottom() {        const node = divRef.current;        node.scrollTop = node.scrollHeight;      }    };  }, []);  let comments = [];  for (let i = 0; i < 50; i++) {    comments.push(<p key={i}>Comment #{i}</p>);  }  return (    <div className="CommentList" ref={divRef}>      {comments}    </div>  );});export default CommentList;

信息输入部分 AddComment 的代码为。rSm28资讯网——每日最新资讯28at.com

import { forwardRef, useRef, useImperativeHandle } from 'react';const AddComment = forwardRef(function AddComment(props, ref) {  return <input placeholder="Add comment..." ref={ref} />;});export default AddComment;

Post 要把他们整合起来。rSm28资讯网——每日最新资讯28at.com

import { forwardRef, useRef, useImperativeHandle } from 'react';import CommentList from './CommentList.js';import AddComment from './AddComment.js';const Post = forwardRef((props, ref) => {  const commentsRef = useRef(null);  const addCommentRef = useRef(null);  useImperativeHandle(ref, () => {    return {      scrollAndFocusAddComment() {        commentsRef.current.scrollToBottom();        addCommentRef.current.focus();      }    };  }, []);  return (    <>      <article>        <p>Welcome to my blog!</p>      </article>      <CommentList ref={commentsRef} />      <AddComment ref={addCommentRef} />    </>  );});export default Post;

这样,我们整个案例的代码就写完了。useRef、useImprativeHandle、forwardRef 一起配合帮助我们完成了这个功能。rSm28资讯网——每日最新资讯28at.com

本文链接:http://www.28at.com/showinfo-26-65368-0.htmlReact高手都善于使用useImprativeHandle

声明:本网页内容旨在传播知识,若有侵权等问题请及时与本网联系,我们将在第一时间删除处理。邮件:2376512515@qq.com

上一篇: 从 SQLlin 的更新看 Kotlin Multiplatform 技术更迭

下一篇: Go 日期时间包装器:15 条更便捷的时间处理

标签:
  • 热门焦点
  • 6月iOS设备好评榜:第一蝉联榜首近一年

    6月iOS设备好评榜:第一蝉联榜首近一年

    作为安兔兔各种榜单里变化最小的那个,2023年6月的iOS好评榜和上个月相比没有任何排名上的变化,仅仅是部分设备好评率的下降,长年累月的用户评价和逐渐退出市场的老款机器让这
  • 三言两语说透设计模式的艺术-单例模式

    三言两语说透设计模式的艺术-单例模式

    写在前面单例模式是一种常用的软件设计模式,它所创建的对象只有一个实例,且该实例易于被外界访问。单例对象由于只有一个实例,所以它可以方便地被系统中的其他对象共享,从而减少
  • Flowable工作流引擎的科普与实践

    Flowable工作流引擎的科普与实践

    一.引言当我们在日常工作和业务中需要进行各种审批流程时,可能会面临一系列技术和业务上的挑战。手动处理这些审批流程可能会导致开发成本的增加以及业务复杂度的上升。在这
  • 让我们一起聊聊文件的操作

    让我们一起聊聊文件的操作

    文件【1】文件是什么?文件是保存数据的地方,是数据源的一种,比如大家经常使用的word文档、txt文件、excel文件、jpg文件...都是文件。文件最主要的作用就是保存数据,它既可以保
  • 慕岩炮轰抖音,百合网今何在?

    慕岩炮轰抖音,百合网今何在?

    来源:价值研究所 作者:Hernanderz&ldquo;难道就因为自己的一个产品牛逼了,从客服到总裁,都不愿意正视自己产品和运营上的问题,选择逃避了吗?&rdquo;这一番话,出自百合网联合创
  • 拼多多APP上线本地生活入口,群雄逐鹿万亿市场

    拼多多APP上线本地生活入口,群雄逐鹿万亿市场

    Tech星球(微信ID:tech618)文 | 陈桥辉 Tech星球独家获悉,拼多多在其APP内上线了&ldquo;本地生活&rdquo;入口,位置较深,位于首页的&ldquo;充值中心&rdquo;内,目前主要售卖美食相关的
  • onebot M24巧系列一体机采用轻薄机身设计,现已在各平台开售

    onebot M24巧系列一体机采用轻薄机身设计,现已在各平台开售

    onebot M24 巧系列一体机目前已在线上线下各平台同步开售。onebot M24 巧系列采用一体化轻薄机身设计,最薄处为 10.15mm,拥有宝石红、午夜蓝、石墨绿、雅致
  • 微软发布Windows 11新版 引入全新任务栏状态

    微软发布Windows 11新版 引入全新任务栏状态

    近日,微软发布了Windows 11新版,而Build 22563更新主要引入了几周前曝光的平板模式任务栏等,系统更流畅了。更新中,Windows 11加入了专门针对平板优化的任务栏
  • 三翼鸟智能家居亮相电博会,让用户体验更真实

    三翼鸟智能家居亮相电博会,让用户体验更真实

    2021电博会在青岛国际会展中心开幕中,三翼鸟直接把“家”搬到了现场,成为了展会的一大看点。这也是三翼鸟继9月9日发布了行业首个一站式定制智慧家平台后的
Top