概述

React Hooks 是 React 16.8 引入的新特性,允许在函数组件中使用状态和其他 React 特性。根据数据的使用场景和更新机制,可以将 Hooks 分为三大类:

1. 保存只读数据

useMemo

用途: 缓存计算结果,避免重复计算

语法:

const memoizedValue = useMemo(() => computeExpensiveValue(a, b), [a, b]);

特点:

  • 只有当依赖项发生变化时才重新计算
  • 适用于计算量大的操作
  • 返回缓存的值

使用场景:

// 复杂计算
const expensiveValue = useMemo(() => {return items.filter((item) => item.price > 100).map((item) => ({...item,discount: item.price * 0.1,}));
}, [items]);// 对象/数组缓存
const memoizedObject = useMemo(() => ({id: user.id,name: user.name,avatar: user.avatar,}),

[user.id, user.name, user.avatar]

);

useCallback

用途: 缓存函数,避免子组件不必要的重新渲染

语法:

const memoizedCallback = useCallback(() => {doSomething(a, b);
}, [a, b]);

特点:

  • 只有当依赖项变化时才创建新的函数
  • 主要用于性能优化
  • 返回缓存的函数引用

使用场景:

// 传递给子组件的回调函数
const handleClick = useCallback((id) => {setSelectedId(id);fetchUserDetails(id);
}, []);// 事件处理函数
const handleSubmit = useCallback((formData) => {submitForm(formData);},[submitForm]
);// 子组件优化
const ChildComponent = React.memo(({ onUpdate }) => {return <button onClick={onUpdate}>更新</button>;
});

2. 保存可变数据,更改时触发渲染

useState

用途: 管理组件内的简单状态

语法:

const [state, setState] = useState(initialState);

特点:

  • 状态更新会触发组件重新渲染
  • 异步更新,多个 setState 会被批处理
  • 适合简单的状态管理

使用场景:

// 基础状态管理
const [count, setCount] = useState(0);
const [name, setName] = useState("");
const [isLoading, setIsLoading] = useState(false);// 对象状态
const [user, setUser] = useState({name: "",email: "",age: 0,
});// 函数式更新
setCount((prevCount) => prevCount + 1);
setUser((prevUser) => ({...prevUser,name: "新名字",
}));

useReducer

用途: 管理复杂的状态逻辑

语法:

const [state, dispatch] = useReducer(reducer, initialState, init);

特点:

  • 状态更新逻辑集中管理
  • 适合复杂的状态转换
  • 可以处理多个相关的状态

使用场景:

// 定义 reducer
const todoReducer = (state, action) => {switch (action.type) {case "ADD_TODO":return {...state,todos: [...state.todos, action.payload],};case "TOGGLE_TODO":return {...state,todos: state.todos.map((todo) =>todo.id === action.payload? { ...todo, completed: !todo.completed }: todo),};case "DELETE_TODO":return {...state,todos: state.todos.filter((todo) => todo.id !== action.payload),};default:return state;}
};// 使用 useReducer
const [state, dispatch] = useReducer(todoReducer, {todos: [],filter: "all",
});// 分发 action
dispatch({ type: "ADD_TODO", payload: { id: 1, text: "学习 React" } });
dispatch({ type: "TOGGLE_TODO", payload: 1 });

3. 保存可变数据,更改时不触发渲染

useRef

用途: 保存可变值,不触发重新渲染

语法:

const refContainer = useRef(initialValue);

特点:

  • 值的变化不会触发组件重新渲染
  • 可以访问 DOM 元素
  • 适合存储不需要触发渲染的数据

使用场景:

// 访问 DOM 元素
const inputRef = useRef(null);
const focusInput = () => {inputRef.current.focus();
};// 存储定时器 ID
const timerRef = useRef(null);
useEffect(() => {timerRef.current = setInterval(() => {console.log("定时器执行");}, 1000);return () => {if (timerRef.current) {clearInterval(timerRef.current);}};
}, []);// 存储前一次的值
const prevCountRef = useRef();
useEffect(() => {prevCountRef.current = count;
});// 存储实例变量
const instanceRef = useRef({isMounted: false,data: null,
});

最佳实践

性能优化

// 1. 合理使用 useMemo 和 useCallback
const expensiveValue = useMemo(() => {return heavyComputation(data);
}, [data]);const handleClick = useCallback(() => {// 处理点击事件
}, [dependencies]);// 2. 避免在渲染中创建对象/函数
// ❌ 错误做法
const Component = () => {const [count, setCount] = useState(0);// 每次渲染都会创建新对象const style = { color: "red" };const handleClick = () => setCount(count + 1);return (<div style={style} onClick={handleClick}>{count}</div>);
};// ✅ 正确做法
const Component = () => {const [count, setCount] = useState(0);const style = useMemo(() => ({ color: "red" }), []);const handleClick = useCallback(() => setCount((prev) => prev + 1), []);return (<div style={style} onClick={handleClick}>{count}</div>);
};

状态管理选择

// 简单状态 - 使用 useState
const [isVisible, setIsVisible] = useState(false);
const [userName, setUserName] = useState("");// 复杂状态 - 使用 useReducer
const [formState, dispatch] = useReducer(formReducer, {fields: {},errors: {},isValid: false,
});// 不需要渲染的数据 - 使用 useRef
const previousValue = useRef(null);
const timeoutId = useRef(null);

依赖项管理

// 1. 正确设置依赖项
useEffect(() => {fetchData(userId);
}, [userId]); // 包含所有依赖项// 2. 使用 useCallback 避免依赖项变化
const fetchData = useCallback((id) => {// 获取数据逻辑
}, []); // 空依赖数组// 3. 使用 useRef 存储最新值
const latestValue = useRef(value);
useEffect(() => {latestValue.current = value;
});useEffect(() => {const timer = setInterval(() => {console.log(latestValue.current); // 总是获取最新值}, 1000);return () => clearInterval(timer);
}, []); // 不需要依赖 value

常见陷阱

1. 过度优化

// ❌ 不必要的 useMemo
const simpleValue = useMemo(() => count + 1, [count]);// ✅ 直接计算
const simpleValue = count + 1;

2. 依赖项遗漏

// ❌ 遗漏依赖项
useEffect(() => {console.log(count);
}, []); // 缺少 count 依赖// ✅ 正确设置依赖项
useEffect(() => {console.log(count);
}, [count]);

3. 闭包陷阱

// ❌ 闭包陷阱
const [count, setCount] = useState(0);
const handleClick = useCallback(() => {console.log(count); // 总是打印初始值
}, []); // 空依赖数组// ✅ 解决方案 1: 添加依赖项
const handleClick = useCallback(() => {console.log(count);
}, [count]);// ✅ 解决方案 2: 使用函数式更新
const handleClick = useCallback(() => {setCount((prevCount) => {console.log(prevCount);return prevCount + 1;});
}, []);

总结

选择合适的 Hook 取决于具体的使用场景:

  • useMemo/useCallback: 用于性能优化,缓存计算结果和函数
  • useState/useReducer: 用于状态管理,状态变化会触发重新渲染
  • useRef: 用于存储不需要触发渲染的可变数据

合理使用这些 Hook 可以提升组件性能,避免不必要的重新渲染,同时保持代码的可读性和可维护性。

 React Hooks 完全指南:从基础到高级的实战技巧 - 高质量源码分享平台-免费下载各类网站源码与模板及前沿技术分享

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。
如若转载,请注明出处:http://www.pswp.cn/bicheng/95185.shtml
繁体地址,请注明出处:http://hk.pswp.cn/bicheng/95185.shtml
英文地址,请注明出处:http://en.pswp.cn/bicheng/95185.shtml

如若内容造成侵权/违法违规/事实不符,请联系英文站点网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

PCIe 6.0 vs 5.0:带宽翻倍背后的技术革命

PCIe 6.0 vs 5.0&#xff1a;带宽翻倍背后的技术革命在数据中心、AI计算和高速存储需求爆炸式增长的今天&#xff0c;传统接口带宽已成为系统性能提升的瓶颈。PCIe 6.0的推出正是为了解决这一挑战&#xff0c;它通过革命性的技术创新&#xff0c;在保持向后兼容的同时实现了带宽…

突破传统企业组网瓶颈:某科技公司智能组网服务项目深度解析

在现代企业的数字化转型过程中&#xff0c;稳定、高效、安全的网络基础设施已成为业务发展的关键。然而&#xff0c;传统组网方案往往面临诸多挑战&#xff0c;如网络性能不足、组网复杂度高、扩展性不佳、以及安全防护薄弱等问题。为了解决这些痛点&#xff0c;某科技公司通过…

ubuntu单机实现10000个连接同时在线测试

连接前 成功连接后 前端测试连接脚本: c_5k.sh !/bin/bash ulimit -n 100000 # client_simulator.sh SERVER_IP="192.168.0.106" SERVER_PORT=8080 MAX_CLIENTS=5000 BATCH_SIZE=100echo "Starting $MAX_CLIENTS clients to $SERVER_IP:$SERVER_PORT"…

防护墙技术(一):NAT

###源NAT基本原理 NAT&#xff08;Network Address Translation&#xff09;网络地址转换技术 源NAT技术对IP报文的源地址进行转换&#xff0c;将私有IP地址转换为公网IP地址&#xff0c;使大量私网用户可以利用少量公网IP地址访问internet&#xff0c;大大减少对公网IP的消耗 …

动态规划2(c++)

酒鬼#include <bits/stdc.h> using namespace std; int main() {int n;cin>>n;int a[10010];for(int i 1;i<n;i){cin>>a[i];}int dp[1010][5] {0};dp[0][0] 0;dp[1][0] 0;dp[1][1] a[1];dp[1][2] 0;dp[2][0] a[1];dp[2][1] a[2];dp[2][2] a[1]a[…

「LangChain 学习笔记」LangChain大模型应用开发:代理 (Agent)

「LangChain大模型应用开发」 系列文章目录&#xff1a; LangChain大模型应用开发&#xff1a;模型&#xff0c;提示和输出解释器 LangChain大模型应用开发&#xff1a;储存(Memory) LangChain大模型应用开发&#xff1a;模型链&#xff08;Chains&#xff09; LangChain大模…

python pyqt5开发DoIP上位机【介绍】

目录文章合集一、核心功能概述二、主要模块解析1. 导入的库2. 辅助函数3. DOIP协议处理&#xff08;DOIPProtocol类&#xff09;4. 网络工具&#xff08;NetworkUtils类&#xff09;5. 通信线程&#xff08;DOIPCommunicationThread类&#xff09;6. UDS命令输入组件&#xff0…

从零实现一个可扩展的规则解析引擎 —— 支持 AND/OR 优先级、短路求值与多类型运算符

在日常业务开发中&#xff0c;我们经常需要基于一些“规则”来决定程序的走向。比如&#xff1a; 客服机器人 根据用户问题领域和复杂度选择不同的模型&#xff1b;营销系统 根据用户画像匹配不同优惠券&#xff1b;风控引擎 根据请求参数、时间、分值判定是否放行。 这些规则往…

Preprocessing Model in MPC 3 - 基于同态加密的协议 - Over Rings 环

参考论文&#xff1a;SoK: Multiparty Computation in the Preprocessing Model MPC (Secure Multi-Party Computation) 博士生入门资料。抄袭必究。 本系列教程将逐字解读参考论文(以下简称MPCiPPM)&#xff0c;在此过程中&#xff0c;将论文中涵盖的40篇参考文献进行梳理与讲…

uni-app 跨平台项目的 iOS 上架流程:多工具组合的高效协作方案

跨平台框架的兴起&#xff0c;让许多团队选择 uni-app 来开发移动应用。 一套代码多端运行&#xff0c;确实大大降低了研发成本&#xff0c;但当项目进入 iOS 上架阶段 时&#xff0c;很多团队依旧面临挑战&#xff1a;证书复杂、环境不统一、上传繁琐。 本文结合实战经验&…

掌握 Linux 文件权限:chown 命令深度解析与实践

在 Linux 系统的日常运维与开发工作里&#xff0c;文件权限管理是保障系统安全、规范文件访问的关键环节。其中&#xff0c;chown 命令作为修改文件所有者及关联组的核心工具&#xff0c;对精准把控文件权限起着重要作用。接下来&#xff0c;我们将全面拆解 chown 命令&#xf…

计算机算术7-浮点基础知识

1. 浮点表示其中b表示基底&#xff0c;e表示指数&#xff0c;s表示尾数&#xff0c;注意在s的表示过程中&#xff0c;有个隐藏1.同时还有个符号位从下面这个图可以看出&#xff0c;向上溢出和向下溢出的概念&#xff0c;overflow表示的是数的绝对值超过了最大的表示范围&#x…

设计模式8-命令模式

定义 Command Partern: 将一个请求封装成一个对象&#xff0c;从而让你使用不同的请求把客户端参数化&#xff0c;对请求排队或者记录请求日志&#xff0c;可以提供命令的撤销和恢复功能。&#xff08;核心思想是将“动作”与“执行者”解耦&#xff09; 场景 GUI&#xff1a;…

数据结构(顺序表力扣刷题)

1.移除元素 给你一个数组 nums 和一个值 val&#xff0c;你需要 原地 移除所有数值等于 val 的元素。元素的顺序可能发生改变。然后返回 nums 中与 val 不同的元素的数量。 假设 nums 中不等于 val 的元素数量为 k&#xff0c;要通过此题&#xff0c;您需要执行以下操作&…

机器学习 - Kaggle项目实践(6)Dogs vs. Cats Redux: Kernels Edition 猫狗二分类

Dogs vs. Cats Redux: Kernels Edition | Kaggle 任务&#xff1a;给定猫狗图像数据集 进行二分类。 Cats or Dogs - using CNN with Transfer Learning | Kaggle&#xff08;参考&#xff09; Cats or Dogs | Kaggle &#xff08;我的kaggle&#xff09; 本文介绍了使用Re…

基础的汇编指令

目录 1、接上一个csdn特殊功能寄存器 1.1CPSR寄存器 1.2SPSR寄存器 1.3CPSR寄存器的高四位和第四位 ​编辑 2、汇编指令的分类 3、汇编指令的基本格式 4、数据搬移指令&#xff08;赋值指令&#xff09; 4.1指令码 4.2指令格式 4.3测试代码 4.5立即数 4.6ldr伪指令 …

Docker实战避坑指南:从入门到精通

摘要&#xff1a;文人结合自身微服务实践&#xff0c;系统梳理从安装适配、镜像拉取&#xff0c;到运行配置、构建优化、多容器编排、数据持久化、监控运维等 Docker 全流程高频踩坑点&#xff0c;给出可落地的解决方案&#xff0c;帮助读者快速规避同类问题并提升容器化效率。…

《Bishop PRML》10.1. Variational Inference(2)理解VAE

通过VAE与AE理解变分分布的变量 如何理解变分推断公式中,Z和X的含义是什么? 知乎 变分自编码器VAE的数学原理。 csdn 变分自编码器(VAE)的数学原理以及实现 Loss functions in Variational Autoencoders (VAEs) 一文解释 VAE+ELBO AE的编码和解码是确定性的。VAE的解码过程…

函数调用中的初始化与赋值——深入理解C++对象的生命周期

技术博客&#xff1a;函数调用中的初始化与赋值——深入理解C对象的生命周期引言在C编程中&#xff0c;理解函数调用过程中参数传递、对象创建和返回值处理的细节对于编写高效且无误的代码至关重要。本文将通过一个具体的例子来探讨函数调用时实参到形参的转换过程&#xff0c;…

矩阵微积分的链式法则(chain rule)

矩阵微积分的链式法则&#xff08;chain rule&#xff09;与标量情况一样&#xff0c;用于求复合函数的导数&#xff0c;但由于涉及矩阵和向量的求导&#xff0c;维度匹配和布局约定&#xff08;numerator-layout vs. denominator-layout&#xff09;必须格外小心。下面给出常见…