高效管理 React 状态和交互:我的自定义 Hooks 实践
高效管理 React 状态和交互:自定义 Hooks 实践
在 React 中,Hooks 是一种使我们能够在函数组件中使用状态和副作用的强大工具。随着项目的增大,重复的逻辑可能会出现在多个组件中,这时使用自定义 Hooks 就非常合适。它们帮助我们将业务逻辑抽象成独立的功能模块,提升代码的可复用性和可维护性。
本文将介绍一些常见的自定义 Hook 实践,包括数据获取、去抖、状态切换、本地存储管理和点击外部区域关闭组件等。通过这些自定义 Hook,我们能够高效管理应用的状态和交互逻辑。
1. useFetch
- 数据获取 Hook
useFetch
是一个处理数据获取请求的自定义 Hook。它封装了 fetch
请求的逻辑,并提供了 loading
和 error
状态,方便组件根据请求状态渲染不同的内容。
代码实现
import { useState, useEffect } from "react";function useFetch<T>(url: string) {const [data, setData] = useState<T | null>(null);const [loading, setLoading] = useState(true);const [error, setError] = useState<Error | null>(null);useEffect(() => {const fetchData = async () => {setLoading(true);try {const response = await fetch(url);if (!response.ok) throw new Error("Network response was not ok");const result = await response.json();setData(result);} catch (err) {setError(err as Error);} finally {setLoading(false);}};fetchData();}, [url]);return { data, loading, error };
}export default useFetch;
使用示例
const { data, loading, error } = useFetch<User[]>('/api/users');if (loading) return <p>Loading...</p>;
if (error) return <p>Error: {error.message}</p>;return <ul>{data?.map(user => <li key={user.id}>{user.name}</li>)}</ul>;
在上述实现中,useFetch
Hook 提供了一个简洁的方式来处理 API 请求,同时通过 loading
和 error
状态来管理加载中的 UI 和错误展示。它封装了所有的异步逻辑,避免了在每个组件中重复写 fetch
请求。
2. useDebounce
- 防抖处理
防抖用于避免在用户输入时频繁触发事件,尤其是在搜索框、自动完成等场景中。useDebounce
实现了延迟值的更新,直到用户停止输入一段时间后才触发。
代码实现
import { useState, useEffect } from "react";function useDebounce<T>(value: T, delay: number): T {const [debouncedValue, setDebouncedValue] = useState(value);useEffect(() => {const handler = setTimeout(() => setDebouncedValue(value), delay);return () => clearTimeout(handler);}, [value, delay]);return debouncedValue;
}export default useDebounce;
使用示例
const [searchTerm, setSearchTerm] = useState("");
const debouncedSearchTerm = useDebounce(searchTerm, 500);useEffect(() => {// 发起 API 请求或执行其他操作console.log(debouncedSearchTerm);
}, [debouncedSearchTerm]);
在上述例子中,useDebounce
延迟了对输入值的响应,从而避免了在用户每次输入时都发起请求。它的使用非常适合搜索框和过滤功能,能够提高性能。
3. useToggle
- 简化状态切换
useToggle
是一个简化布尔值状态切换的 Hook,适用于需要频繁切换状态的场景,如显示/隐藏弹窗、展开/收起菜单等。
代码实现
import { useState } from "react";function useToggle(initialState = false) {const [state, setState] = useState(initialState);const toggle = () => setState(prev => !prev);return [state, toggle] as const;
}export default useToggle;
使用示例
const [isOpen, toggle] = useToggle(false);return (<div><button onClick={toggle}>Toggle</button>{isOpen && <p>Content is visible!</p>}</div>
);
useToggle
可以非常简洁地处理布尔类型状态的切换,避免在组件中写冗余的 setState
代码。
4. useLocalStorage
- 本地存储管理
useLocalStorage
是一个与 localStorage
配合的 Hook,它能够自动处理数据的获取、存储和更新,确保数据在页面刷新后仍然保持。
代码实现
import { useState } from "react";function useLocalStorage<T>(key: string, initialValue: T) {const [storedValue, setStoredValue] = useState<T>(() => {try {const item = window.localStorage.getItem(key);return item ? JSON.parse(item) : initialValue;} catch (error) {console.error(error);return initialValue;}});const setValue = (value: T) => {try {setStoredValue(value);window.localStorage.setItem(key, JSON.stringify(value));} catch (error) {console.error(error);}};return [storedValue, setValue] as const;
}export default useLocalStorage;
使用示例
const [name, setName] = useLocalStorage("name", "John Doe");return (<div><p>Your name is: {name}</p><button onClick={() => setName("Jane Doe")}>Change Name</button></div>
);
通过 useLocalStorage
,我们不仅能够轻松地获取和设置 localStorage
中的数据,还能在刷新页面后保持数据状态,适用于保存用户设置、主题等信息。
5. useClickOutside
- 外部点击监听
useClickOutside
是一个帮助我们监听用户点击外部区域的 Hook,常用于实现点击外部区域关闭弹窗、菜单等交互功能。
代码实现
import { useEffect, useRef } from "react";function useClickOutside(handler: () => void) {const ref = useRef<HTMLDivElement>(null);useEffect(() => {const handleClickOutside = (event: MouseEvent) => {if (ref.current && !ref.current.contains(event.target as Node)) {handler();}};document.addEventListener('mousedown', handleClickOutside);return () => document.removeEventListener('mousedown', handleClickOutside);}, [handler]);return ref;
}export default useClickOutside;
使用示例
const [isOpen, setIsOpen] = useState(false);
const closeDropdown = () => setIsOpen(false);
const dropdownRef = useClickOutside(closeDropdown);return (<div><button onClick={() => setIsOpen(!isOpen)}>Toggle Dropdown</button>{isOpen && (<div ref={dropdownRef} style={{ border: '1px solid black', padding: '10px' }}><p>Dropdown content</p></div>)}</div>
);
useClickOutside
使得我们能够简化对点击外部区域的监听逻辑,减少了冗余代码,提高了交互体验。
总结
自定义 Hook 是 React 开发中非常强大的工具,可以帮助我们复用逻辑,减少冗余代码,提升组件的可维护性和可读性。通过本文介绍的几个常见自定义 Hook(如 useFetch
、useDebounce
、useToggle
、useLocalStorage
和 useClickOutside
),我们可以轻松应对许多常见的开发需求,提高应用的性能和用户体验。
希望通过这些实用的自定义 Hook,你能够更高效地管理 React 中的状态和交互逻辑,打造更优雅的代码结构!
相关文章:
高效管理 React 状态和交互:我的自定义 Hooks 实践
高效管理 React 状态和交互:自定义 Hooks 实践 在 React 中,Hooks 是一种使我们能够在函数组件中使用状态和副作用的强大工具。随着项目的增大,重复的逻辑可能会出现在多个组件中,这时使用自定义 Hooks 就非常合适。它们帮助我们…...
ESP 32控制无刷电机2
import machine import time import socket import network from machine import I2C, Pin, ADC def start_ap(): """ 启动ESP32的AP模式 """ ap network.WLAN(network.AP_IF) ap.active(True) ssid ESP32_APTest …...
揭开人工智能中 Tokens 的神秘面纱
揭开人工智能中 Tokens 的神秘面纱 在人工智能,尤其是自然语言处理(NLP)领域,"tokens" 是一个频繁出现且至关重要的概念。对于理解语言模型如何处理和理解人类语言,tokens 起着基础性的作用。那么ÿ…...
萌新学 Python 之 random 函数
random 模块:主要用来生成随机数 先导入包:import random randint(a, b),生成 [a, b] 之间的整数,包含边界 a 和 b,a 和 b 为整数 random(),生成的是 [0,1) 之间的浮点数,包含 0 不包含 1 r…...
2-2linux系统IO
文章目录 linux系统文件io1 open /close1.1 open1.2 close1.3 示例1.3.1 打开已经存在的文件 2 read/write2.1 read2.2 write使用 遗留问题:新创建的文件权限很奇怪3 lseek3.1 文件指针的移动3.2 文件拓展 perror函数 linux系统文件io 系统函数是系统专有的函数&am…...

周边游平台设计与实现(代码+数据库+LW)
摘 要 在如今社会上,关于信息上面的处理,没有任何一个企业或者个人会忽视,如何让信息急速传递,并且归档储存查询,采用之前的纸张记录模式已经不符合当前使用要求了。所以,对旅游信息管理的提升,…...

视频批量分段工具
参考原文:视频批量分段工具 选择视频文件 当您启动这款视频批量分段工具程序后,有两种便捷的方式来选择要处理的视频文件。其一,您可以点击程序界面中的 “文件” 菜单,在下拉选项里找到 “选择视频文件” 按钮并点击;…...
Android -- 使用Sharepreference保存List储存失败,原因是包含Bitmap,drawable等类型数据
1.报错信息如下: class android.content.res.ColorStateList declares multiple JSON fields named mChangingConfigurations 2.Bean类属性如下: data class AppInfoBean( val appName: String?, val appIcon: Drawable, val appPackage: String?,…...

java项目之基于ssm的图书馆书库管理系统(源码+文档)
风定落花生,歌声逐流水,大家好我是风歌,混迹在java圈的辛苦码农。今天要和大家聊的是一款基于ssm的图书馆书库管理系统。项目源码以及部署相关请联系风歌,文末附上联系信息 。 项目简介: 该系统可以实现图书信息管理…...
编写一个程序,输入一个数字并输出其阶乘(Python版)
编写一个程序,输入一个数字并输出其阶乘 要计算一个数字的阶乘,可以编写一个简单的 Python 程序,使用循环或者递归来实现: 1. 使用 for 循环计算阶乘 # 输入一个数字 num int(input("请输入一个数字: "))# 初始化阶乘结果 facto…...
dify基础之prompts
摘要:在大型语言模型(LLM)应用中,Prompt(提示词)是连接用户意图与模型输出的核心工具。本文从概念、组成、设计原则到实践案例,系统讲解如何通过Prompt解锁LLM的潜能,提升生成内容的…...
实践教程:使用DeepSeek实现PDF转Word的高效方案
🎈Deepseek推荐工具 PDF文件因其跨平台、格式稳定的特性被广泛使用,但在内容编辑场景中,用户常需将PDF转换为可编辑的Word文档。传统的付费工具(如Adobe Acrobat)或在线转换平台存在成本高、隐私风险等问题。本文将使…...

网络安全审计员
在当今数字化时代,随着信息技术的迅猛发展,网络安全问题日益凸显,成为各行各业不容忽视的重要议题。特别是对于企业、政府机构等组织而言,网络安全不仅关乎数据资产的安全,更与组织的声誉、客户信任乃至法律法规的遵从…...
算法-二叉树篇13-路径总和
路径总和 力扣题目链接 题目描述 给你二叉树的根节点 root 和一个表示目标和的整数 targetSum 。判断该树中是否存在 根节点到叶子节点 的路径,这条路径上所有节点值相加等于目标和 targetSum 。如果存在,返回 true ;否则,返回…...

如何设计一个短链系统?
短链系统设计的关键要点: 系统功能实现 短链生成:接收长链接,先检查是否已有对应短链,存在则直接返回。否则,使用分布式 ID 生成器(如号段模式、SnowFlake 算法、数据库自增 ID、Redis 自增等)生成唯一 ID,或通过哈希算法(如 MurmurHash)处理长链接得到哈希值。再将生…...

医疗行业电脑终端如何防病毒——火绒企业版杀毒软件
医疗物联网技术广泛应用,使得医院网络空间中增加了诸多新型终端设备。这些设备类型多样、型号各异,风险暴露面积大。火绒安全对医疗机构终端安全出现的问题、不足、需求等,提出整体解决方案。 医疗行业终端安全防护痛点 系统老旧 医院、区…...

云平台DeepSeek满血版:引领AI推理革新,开启智慧新时代
引言:人工智能的未来——云平台的卓越突破 在当今科技飞速发展的时代,人工智能(AI)技术正深刻地改变着我们生活与工作方式的方方面面。作为AI领域的创新者与领航者,云平台始终走在技术前沿,凭借无穷的热情…...
Java进阶——数据类型深入解析
Java数据类型深入解析 本文主要介绍 Java 数据类型的相关知识,包括8 种基本类型、默认值、字面量表示、自动装箱与拆箱、类型转换规则(隐式转换、强制转换)、浮点型精度问题、字符与字符串、引用类型比较与常量池、数值溢出与处理、类型推断等…...

R语言+AI提示词:贝叶斯广义线性混合效应模型GLMM生物学Meta分析
全文链接:https://tecdat.cn/?p40797 本文旨在帮助0基础或只有简单编程基础的研究学者,通过 AI 的提示词工程,使用 R 语言完成元分析,包括数据处理、模型构建、评估以及结果解读等步骤(点击文末“阅读原文”获取完整代…...

深度解析 ANSI X9.31 TR-31:金融行业密钥管理核心标准20250228
深度解析 ANSI X9.31 TR-31:金融行业密钥管理核心标准 在当今数字化金融时代,信息安全至关重要,而密钥管理则是保障金融数据安全的核心环节。ANSI X9.31 TR-31作为金融行业密钥管理的关键标准,为对称密钥的全生命周期管理提供了坚…...

stm32G473的flash模式是单bank还是双bank?
今天突然有人stm32G473的flash模式是单bank还是双bank?由于时间太久,我真忘记了。搜搜发现,还真有人和我一样。见下面的链接:https://shequ.stmicroelectronics.cn/forum.php?modviewthread&tid644563 根据STM32G4系列参考手…...

Mybatis逆向工程,动态创建实体类、条件扩展类、Mapper接口、Mapper.xml映射文件
今天呢,博主的学习进度也是步入了Java Mybatis 框架,目前正在逐步杨帆旗航。 那么接下来就给大家出一期有关 Mybatis 逆向工程的教学,希望能对大家有所帮助,也特别欢迎大家指点不足之处,小生很乐意接受正确的建议&…...

centos 7 部署awstats 网站访问检测
一、基础环境准备(两种安装方式都要做) bash # 安装必要依赖 yum install -y httpd perl mod_perl perl-Time-HiRes perl-DateTime systemctl enable httpd # 设置 Apache 开机自启 systemctl start httpd # 启动 Apache二、安装 AWStats࿰…...

从零开始打造 OpenSTLinux 6.6 Yocto 系统(基于STM32CubeMX)(九)
设备树移植 和uboot设备树修改的内容同步到kernel将设备树stm32mp157d-stm32mp157daa1-mx.dts复制到内核源码目录下 源码修改及编译 修改arch/arm/boot/dts/st/Makefile,新增设备树编译 stm32mp157f-ev1-m4-examples.dtb \stm32mp157d-stm32mp157daa1-mx.dtb修改…...

《基于Apache Flink的流处理》笔记
思维导图 1-3 章 4-7章 8-11 章 参考资料 源码: https://github.com/streaming-with-flink 博客 https://flink.apache.org/bloghttps://www.ververica.com/blog 聚会及会议 https://flink-forward.orghttps://www.meetup.com/topics/apache-flink https://n…...

【Oracle】分区表
个人主页:Guiat 归属专栏:Oracle 文章目录 1. 分区表基础概述1.1 分区表的概念与优势1.2 分区类型概览1.3 分区表的工作原理 2. 范围分区 (RANGE Partitioning)2.1 基础范围分区2.1.1 按日期范围分区2.1.2 按数值范围分区 2.2 间隔分区 (INTERVAL Partit…...

Linux --进程控制
本文从以下五个方面来初步认识进程控制: 目录 进程创建 进程终止 进程等待 进程替换 模拟实现一个微型shell 进程创建 在Linux系统中我们可以在一个进程使用系统调用fork()来创建子进程,创建出来的进程就是子进程,原来的进程为父进程。…...
Linux离线(zip方式)安装docker
目录 基础信息操作系统信息docker信息 安装实例安装步骤示例 遇到的问题问题1:修改默认工作路径启动失败问题2 找不到对应组 基础信息 操作系统信息 OS版本:CentOS 7 64位 内核版本:3.10.0 相关命令: uname -rcat /etc/os-rele…...
智能AI电话机器人系统的识别能力现状与发展水平
一、引言 随着人工智能技术的飞速发展,AI电话机器人系统已经从简单的自动应答工具演变为具备复杂交互能力的智能助手。这类系统结合了语音识别、自然语言处理、情感计算和机器学习等多项前沿技术,在客户服务、营销推广、信息查询等领域发挥着越来越重要…...
Java数值运算常见陷阱与规避方法
整数除法中的舍入问题 问题现象 当开发者预期进行浮点除法却误用整数除法时,会出现小数部分被截断的情况。典型错误模式如下: void process(int value) {double half = value / 2; // 整数除法导致截断// 使用half变量 }此时...