0

0

掌握 React 中的 useImperativeHandle(使用 TypeScript)

王林

王林

发布时间:2024-09-09 08:21:05

|

904人浏览过

|

来源于dev.to

转载

掌握 react 中的 useimperativehandle(使用 typescript)

使用 typescript 构建 react 应用程序时,开发人员经常遇到需要创建具有高级功能的自定义、可重用组件的场景。本文将探讨两个强大的概念:用于对引用管理进行细粒度控制的 useimperativehandle 挂钩,以及创建表单验证和模态组件等自定义组件。

我们将深入探讨:

  1. useimperativehandle 钩子:它的作用、何时使用它以及它如何允许您自定义父组件可以访问的 ref 值。
  2. 创建表单验证组件:使用 typescript 构建可重用组件进行表单验证的实际示例。
  3. 实现模态组件:另一个示例展示如何使用 typescript 创建交互式且可重用的模态。

这些示例将帮助初学者了解如何利用 typescript 构建交互式和可重用的组件,同时探索引用管理等高级概念。读完本文后,您将为在 react 应用程序中创建强大的自定义组件奠定坚实的基础。

什么是 useimperativehandle?

useimperativehandle 是 react 中的一个钩子,允许您自定义父组件可以访问的 ref 对象。当您想要向父组件公开自定义 api,而不是公开组件的内部实现细节时,这非常有用。

何时以及为何应该使用它

在大多数情况下,useref 提供了足够的功能来访问 dom 元素或组件实例。但是,当您需要更多控制时,useimperativehandle 就会介入,提供一种仅向父组件公开您选择的方法或状态的方法。这可以确保您的组件保持模块化、封装性并且更易于维护。该钩子还允许更好的抽象,这意味着您可以在应用程序中以最少的重复重复使用组件。

示例 1 - 拨动开关组件

此示例演示了如何使用 typescript 创建切换开关组件。组件使用 useimperativehandle 向父组件公开自定义 api,允许父组件控制开关状态。

Napkin AI
Napkin AI

Napkin AI 可以将您的文本转换为图表、流程图、信息图、思维导图视觉效果,以便快速有效地分享您的想法。

下载
  • 用例:创建可由父组件控制的自定义切换开关组件。
  • 实施:
    • 定义组件并使用 useimperativehandle 公开自定义 api。
    • 在父组件中创建一个 ref 并将其传递给 toggleswitch 组件。
    • 使用ref调用自定义api并控制开关状态。
import react, { forwardref, `useimperativehandle`, usestate } from "react";

interface toggleref {
  toggle: () => void;
  getstate: () => boolean;
}

type toggleswitchprops = {
  initialstate?: boolean;
};

const toggleswitch = forwardref<toggleref, toggleswitchprops>((props, ref) => {
  const [istoggled, setistoggled] = usestate(props.initialstate ?? false);

  `useimperativehandle`(ref, () => ({
    toggle: () => setistoggled(!istoggled),
    getstate: () => istoggled,
  }));

  return (
    <motion.button
      onclick={() => setistoggled(!istoggled)}
      classname="flex items-center justify-start w-12 h-6 p-1 overflow-hidden bg-gray-300 rounded-full"
      animate={{
        backgroundcolor: istoggled ? "#4caf50" : "#f44336",
      }}
      transition={{ duration: 0.3 }}
    >
      <motion.div
        classname="flex items-center justify-center w-5 h-5 bg-white rounded-full"
        animate={{
          x: istoggled ? "100%" : "0%",
        }}
        transition={{ type: "spring", stiffness: 700, damping: 100 }}
      ></motion.div>
    </motion.button>
  );
});

function example() {
  const toggleref = useref<toggleref>(null);

  return (
    <div classname="flex flex-col items-center justify-center h-screen gap-4">
      <section classname="flex flex-row items-center justify-center w-full py-4 border border-gray-200 rounded-md gap-x-4">
        <toggleswitch ref={toggleref} />
        <button
          onclick={() => toggleref.current?.toggle()}
          classname="px-4 py-2 text-white bg-blue-500 rounded-md"
        >
          toggle switch
        </button>
      </section>
    </div>
  );
}

示例 2 - 手风琴组件

此示例演示了如何使用 typescript 创建手风琴组件。该组件使用 useimperativehandle 向父组件公开自定义 api,允许父组件控制折叠状态。

  • 用例:创建可由父组件控制的自定义手风琴组件。
  • 实施:
    • 定义组件并使用 useimperativehandle 公开自定义 api。
    • 在父组件中创建一个 ref 并将其传递给 accordion 组件。
    • 使用ref调用自定义api并控制accordion状态。
interface AccordionRef {
  expand: () => void;
  collapse: () => void;
  isExpanded: () => boolean;
  toggle: () => void;
}

type AccordionProps = {
  initialState?: boolean;
  title: string;
  content: ReactNode;
};

const Accordion = forwardRef<AccordionRef, AccordionProps>((props, ref) => {
  const [expanded, setExpanded] = useState(props.initialState ?? false);

  `useImperativeHandle`(ref, () => ({
    expand: () => setExpanded(true),
    collapse: () => setExpanded(false),
    isExpanded: () => expanded,
    toggle: () => setExpanded((prev) => !prev),
  }));

  const handleToggle = () => {
    setExpanded((prev) => !prev);
  };

  return (
    <div className="overflow-hidden border border-gray-200 rounded-md w-ful">
      <motion.button
        className="w-full px-4 py-2 text-left bg-gray-100 hover:bg-gray-200"
        onClick={handleToggle}
        initial={false}
        animate={{ backgroundColor: expanded ? "#e5e7eb" : "#f3f4f6" }}
      >
        {props.title}
      </motion.button>
      <AnimatePresence initial={false}>
        {expanded && (
          <motion.div
            initial="collapsed"
            animate="expanded"
            exit="collapsed"
            variants={{
              expanded: { opacity: 1, height: "auto" },
              collapsed: { opacity: 0, height: 0 },
            }}
            transition={{ duration: 0.3, ease: "easeInOut" }}
          >
            <div className="p-4 bg-white">{props.content}</div>
          </motion.div>
        )}
      </AnimatePresence>
    </div>
  );
});

function Example() {
  const accordionRef = useRef<AccordionRef>(null);

  return (
    <div className="flex flex-col items-center justify-center h-screen gap-4">
      <main className="w-full px-4">
        <Accordion
          ref={accordionRef}
          title="Click to expand"
          content="This is the accordion content. It can contain any text or elements."
        />
      </main>
      <button
        onClick={() => {
          accordionRef.current?.expand();
        }}
        className="px-4 py-2 text-white bg-blue-500 rounded-md disabled:bg-gray-500"
      >
        Expand Accordion
      </button>
      <button
        onClick={() => accordionRef.current?.collapse()}
        className="px-4 py-2 text-white bg-blue-500 rounded-md"
      >
        Collapse Accordion
      </button>
      <button
        onClick={() => accordionRef.current?.toggle()}
        className="px-4 py-2 text-white bg-blue-500 rounded-md"
      >
        Toggle Accordion
      </button>
    </div>
  );
}

使用 useimperativehandle 的优点

useimperativehandle 提供了一些关键的好处,特别是在构建可重用和交互式组件时:

  1. 封装
    通过使用 useimperativehandle,您可以隐藏组件的内部实现细节,并仅公开您希望父级与之交互的方法。这可以确保您的组件保持其内部逻辑,而不受外部因素的影响,使其更加健壮。

  2. 细粒度控制
    它使您可以对 ref 对象进行细粒度控制。您无需公开整个组件实例或 dom 节点,而是可以决定哪些方法或值可用。当使用表单、切换或模态等复杂组件时,这一点至关重要。

  3. 提高可重用性
    通过抽象某些逻辑并控制向父级公开的内容,您的组件可以变得更加可重用。例如,表单验证组件或使用 useimperativehandle 构建的模式可以轻松地在具有不同配置的应用程序的多个部分中重用。

  4. 清除父组件的 api
    您可以为父组件创建一个干净、定义良好的 api,而不是提供对整个组件的直接访问。这会减少错误并提高组件行为的可预测性。

  5. typescript 中更好的类型安全
    借助 typescript,useimperativehandle 变得更加强大。您可以定义父级可以使用的确切方法和属性,从而提高类型安全性并确保开发人员在使用组件时遵循预期的 api。

结论

useimperativehandle 是一个强大的钩子,允许您自定义父组件可以访问的 ref 对象。当您想要向父组件公开自定义 api,而不是公开组件的内部实现细节时,这非常有用。

通过使用useimperativehandle,您可以创建更灵活、更强大的自定义组件,这些组件可以轻松地被父组件重用和自定义。

资源

  • react 文档 - useimperativehandle
  • react 文档 -forwardref
  • react 文档 - useref
  • typescript 文档

热门AI工具

更多
DeepSeek
DeepSeek

幻方量化公司旗下的开源大模型平台

豆包大模型
豆包大模型

字节跳动自主研发的一系列大型语言模型

WorkBuddy
WorkBuddy

腾讯云推出的AI原生桌面智能体工作台

腾讯元宝
腾讯元宝

腾讯混元平台推出的AI助手

文心一言
文心一言

文心一言是百度开发的AI聊天机器人,通过对话可以生成各种形式的内容。

讯飞写作
讯飞写作

基于讯飞星火大模型的AI写作工具,可以快速生成新闻稿件、品宣文案、工作总结、心得体会等各种文文稿

即梦AI
即梦AI

一站式AI创作平台,免费AI图片和视频生成。

ChatGPT
ChatGPT

最最强大的AI聊天机器人程序,ChatGPT不单是聊天机器人,还能进行撰写邮件、视频脚本、文案、翻译、代码等任务。

相关专题

更多
TypeScript工程化开发与Vite构建优化实践
TypeScript工程化开发与Vite构建优化实践

本专题面向前端开发者,深入讲解 TypeScript 类型系统与大型项目结构设计方法,并结合 Vite 构建工具优化前端工程化流程。内容包括模块化设计、类型声明管理、代码分割、热更新原理以及构建性能调优。通过完整项目示例,帮助开发者提升代码可维护性与开发效率。

49

2026.02.13

TypeScript全栈项目架构与接口规范设计
TypeScript全栈项目架构与接口规范设计

本专题面向全栈开发者,系统讲解基于 TypeScript 构建前后端统一技术栈的工程化实践。内容涵盖项目分层设计、接口协议规范、类型共享机制、错误码体系设计、接口自动化生成与文档维护方案。通过完整项目示例,帮助开发者构建结构清晰、类型安全、易维护的现代全栈应用架构。

196

2026.02.25

TypeScript类型系统进阶与大型前端项目实践
TypeScript类型系统进阶与大型前端项目实践

本专题围绕 TypeScript 在大型前端项目中的应用展开,深入讲解类型系统设计与工程化开发方法。内容包括泛型与高级类型、类型推断机制、声明文件编写、模块化结构设计以及代码规范管理。通过真实项目案例分析,帮助开发者构建类型安全、结构清晰、易维护的前端工程体系,提高团队协作效率与代码质量。

48

2026.03.13

DOM是什么意思
DOM是什么意思

dom的英文全称是documentobjectmodel,表示文件对象模型,是w3c组织推荐的处理可扩展置标语言的标准编程接口;dom是html文档的内存中对象表示,它提供了使用javascript与网页交互的方式。想了解更多的相关内容,可以阅读本专题下面的文章。

4349

2024.08.14

TypeScript类型系统进阶与大型前端项目实践
TypeScript类型系统进阶与大型前端项目实践

本专题围绕 TypeScript 在大型前端项目中的应用展开,深入讲解类型系统设计与工程化开发方法。内容包括泛型与高级类型、类型推断机制、声明文件编写、模块化结构设计以及代码规范管理。通过真实项目案例分析,帮助开发者构建类型安全、结构清晰、易维护的前端工程体系,提高团队协作效率与代码质量。

25

2026.03.13

Python异步编程与Asyncio高并发应用实践
Python异步编程与Asyncio高并发应用实践

本专题围绕 Python 异步编程模型展开,深入讲解 Asyncio 框架的核心原理与应用实践。内容包括事件循环机制、协程任务调度、异步 IO 处理以及并发任务管理策略。通过构建高并发网络请求与异步数据处理案例,帮助开发者掌握 Python 在高并发场景中的高效开发方法,并提升系统资源利用率与整体运行性能。

44

2026.03.12

C# ASP.NET Core微服务架构与API网关实践
C# ASP.NET Core微服务架构与API网关实践

本专题围绕 C# 在现代后端架构中的微服务实践展开,系统讲解基于 ASP.NET Core 构建可扩展服务体系的核心方法。内容涵盖服务拆分策略、RESTful API 设计、服务间通信、API 网关统一入口管理以及服务治理机制。通过真实项目案例,帮助开发者掌握构建高可用微服务系统的关键技术,提高系统的可扩展性与维护效率。

177

2026.03.11

Go高并发任务调度与Goroutine池化实践
Go高并发任务调度与Goroutine池化实践

本专题围绕 Go 语言在高并发任务处理场景中的实践展开,系统讲解 Goroutine 调度模型、Channel 通信机制以及并发控制策略。内容包括任务队列设计、Goroutine 池化管理、资源限制控制以及并发任务的性能优化方法。通过实际案例演示,帮助开发者构建稳定高效的 Go 并发任务处理系统,提高系统在高负载环境下的处理能力与稳定性。

50

2026.03.10

Kotlin Android模块化架构与组件化开发实践
Kotlin Android模块化架构与组件化开发实践

本专题围绕 Kotlin 在 Android 应用开发中的架构实践展开,重点讲解模块化设计与组件化开发的实现思路。内容包括项目模块拆分策略、公共组件封装、依赖管理优化、路由通信机制以及大型项目的工程化管理方法。通过真实项目案例分析,帮助开发者构建结构清晰、易扩展且维护成本低的 Android 应用架构体系,提升团队协作效率与项目迭代速度。

92

2026.03.09

热门下载

更多
网站特效
/
网站源码
/
网站素材
/
前端模板

精品课程

更多
相关推荐
/
热门推荐
/
最新课程
关于我们 免责申明 举报中心 意见反馈 讲师合作 广告合作 最新更新
php中文网:公益在线php培训,帮助PHP学习者快速成长!
关注服务号 技术交流群
PHP中文网订阅号
每天精选资源文章推送

Copyright 2014-2026 https://www.php.cn/ All Rights Reserved | php.cn | 湘ICP备2023035733号