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

【React】打卡笔记,入门学习03:useState、useEffect、useRef、useMemo

系列文章目录

提示:这里可以添加系列文章的所有文章的目录,目录需要自己手动添加


提示:写完文章后,目录可以自动生成,如何生成可参考右边的帮助文档

文章目录

  • 系列文章目录
  • 前言
  • 一、`useState` - 状态管理
  • 二、`useRef` - 引用对象
  • 三、`useEffect` - 副作用处理
  • 四、`useMemo` - 缓存 “计算结果”
  • 五、`useCallback` - 缓存 “函数”
  • 总结


前言

提示:这里可以添加本文要记录的大概内容:

苦学react第二周,2025年11月7日14:22:49


提示:以下是本篇文章正文内容,下面案例可供参考

一、useState - 状态管理

作用:在函数组件中管理状态,触发重新渲染。

就是vue的data变量
但是赋值方法跟微信原生小程序一样要用set,定义变量时,前面的是变量名,后面的的赋值方法

// 基本用法
const [state, setState] = useState(initialValue);// 代码中的例子
const [queryParams, setQueryParams] = useState({paymentTime: 'all',dateRange: undefined,// ...
});const [transactions, setTransactions] = useState<Transaction[]>([]);
const [activeIds, setActiveIds] = useState<Set<string>>(new Set());
  • 返回 [当前值, 更新函数]
  • 调用 setState 会触发组件重新渲染
  • 可以传入初始值或函数

二、useRef - 引用对象

作用:创建一个可变的 ref 对象,在组件生命周期内保持引用不变,且更新不会触发重新渲染。

主要用于两种场景:
获取 DOM 元素或组件实例;
存储跨组件渲染周期的 “持久化数据”(修改不会触发组件重渲染)。
语法:const ref = useRef(initialValue)
返回一个ref对象,其current属性用于存储值(初始值为initialValue)

// 基本用法
const ref = useRef(initialValue);// 代码中的例子
const tableRef = useRef<DataTableHandle>(null);
  • .current 可读写
  • 更新 .current 不会触发重新渲染

一般用于:1、保存 DOM 引用; 2、保存子组件实例引用;3、存可变值(如定时器 ID)

// 引入子组件
import DataTable, { type DataTableHandle } from '@/components/table';// DataTable ref
const tableRef = useRef<DataTableHandle>(null);// 通过 ref 调用子组件的方法
tableRef.current?.reset();  // 重置表格到第一页
tableRef.current?.reload(); // 重新加载数据// 页面使用挂载<DataTableref={tableRef}data={dataList}
/>

三、useEffect - 副作用处理

作用:处理组件的 “副作用”(即不属于组件渲染逻辑的操作),例如数据请求、订阅事件、手动修改 DOM、定时器等

语法:useEffect(effectCallback, dependencies)

通俗说就是,既可以当watch监听,又可以当onMounted用

监听器用法如下,后面的数组可以为空,传值则表示任意一值变化就执行

  // 当筛选条件变化时,重置分页到第一页useEffect(() => {tableRef.current?.reset();}, [queryParams.paymentTime,queryParams.dateRange,queryParams.paymentType,queryParams.accountNumber,queryParams.keyword,]);

当做接口请求时,为空就好,就相当于onMounted了。

  useEffect(() => {getCategoryList();}, []);

四、useMemo - 缓存 “计算结果”

缓存计算结果,仅在依赖项变化时重新计算。
这玩意和vue的computed很像,这里我贴出对比代码

// Vue 3 Composition API
import { computed, ref } from 'vue'const firstName = ref('张')
const lastName = ref('三')// computed 会自动追踪依赖
const fullName = computed(() => {return firstName.value + lastName.value
})// 使用:像普通属性一样访问
console.log(fullName.value) // "张三"
// React
import { useMemo, useState } from 'react'const [firstName, setFirstName] = useState('张')
const [lastName, setLastName] = useState('三')// useMemo 需要手动指定依赖
const fullName = useMemo(() => {return firstName + lastName
}, [firstName, lastName]) // 手动指定依赖数组// 使用:直接使用值
console.log(fullName) // "张三"

两者都会在依赖项不变时返回缓存值,避免重复计算。
不同点在于,vue写computed,直接使用参数即可,但是react需要在后面传入,有点类似于useEffect后面那个数组

// Vue 会自动追踪函数内部使用的响应式变量
const total = computed(() => {return items.value.reduce((sum, item) => sum + item.price, 0)// ↑ Vue 自动知道依赖 items
})// React 需要手动列出所有依赖
const total = useMemo(() => {return items.reduce((sum, item) => sum + item.price, 0)
}, [items]) // 必须手动指定依赖

五、useCallback - 缓存 “函数”

说实话这个我有点难理解,按我的想法是,父级列表,在使用子级item组件时。需要传入一些点击事件方法,这些方法就需要加useCallback

下方是示例代码

// 子组件:TodoItem.tsx
import { memo } from 'react';interface TodoItemProps {id: string;text: string;completed: boolean;onToggle: (id: string) => void;  // ← 接收函数onDelete: (id: string) => void;  // ← 接收函数
}// 使用 memo 优化,只有 props 变化时才重新渲染
const TodoItem = memo(({ id, text, completed, onToggle, onDelete }: TodoItemProps) => {console.log(`TodoItem ${id} 渲染了`); // 用于调试return (<div className="flex items-center gap-2"><inputtype="checkbox"checked={completed}onChange={() => onToggle(id)}/><span className={completed ? 'line-through' : ''}>{text}</span><button onClick={() => onDelete(id)}>删除</button></div>);
});export default TodoItem;

分割线

// 父组件:TodoList.tsx
import { useState, useCallback, useMemo } from 'react';
import TodoItem from './TodoItem';interface Todo {id: string;text: string;completed: boolean;
}export default function TodoList() {const [todos, setTodos] = useState<Todo[]>([{ id: '1', text: '学习 React', completed: false },{ id: '2', text: '学习 Vue', completed: false },{ id: '3', text: '学习 TypeScript', completed: true },]);const [filter, setFilter] = useState<'all' | 'active' | 'completed'>('all');const [newTodo, setNewTodo] = useState('');// ❌ 不用 useCallback - 每次渲染都创建新函数// const handleToggle = (id: string) => {//   setTodos(prev => prev.map(todo => //     todo.id === id ? { ...todo, completed: !todo.completed } : todo//   ));// };// ✅ 使用 useCallback - 函数引用保持稳定const handleToggle = useCallback((id: string) => {setTodos(prev => prev.map(todo => todo.id === id ? { ...todo, completed: !todo.completed } : todo));}, []); // 空依赖数组,函数永远不变const handleDelete = useCallback((id: string) => {setTodos(prev => prev.filter(todo => todo.id !== id));}, []);const handleAdd = useCallback(() => {if (newTodo.trim()) {setTodos(prev => [...prev, {id: Date.now().toString(),text: newTodo,completed: false,}]);setNewTodo('');}}, [newTodo]); // 依赖 newTodo// 过滤后的列表(使用 useMemo)const filteredTodos = useMemo(() => {if (filter === 'active') return todos.filter(t => !t.completed);if (filter === 'completed') return todos.filter(t => t.completed);return todos;}, [todos, filter]);return (<div className="p-4"><h1>待办事项列表</h1>{/* 筛选器 */}<div className="mb-4"><button onClick={() => setFilter('all')}>全部</button><button onClick={() => setFilter('active')}>未完成</button><button onClick={() => setFilter('completed')}>已完成</button></div>{/* 添加新待办 */}<div className="mb-4"><inputvalue={newTodo}onChange={(e) => setNewTodo(e.target.value)}placeholder="输入新待办..."/><button onClick={handleAdd}>添加</button></div>{/* 待办列表 */}<div>{filteredTodos.map(todo => (<TodoItemkey={todo.id}id={todo.id}text={todo.text}completed={todo.completed}onToggle={handleToggle}  // ← 使用 useCallback 的函数onDelete={handleDelete}  // ← 使用 useCallback 的函数/>))}</div></div>);
}

性能对比
不用 useCallback:

// ❌ 每次父组件渲染,handleToggle 都是新函数
const handleToggle = (id: string) => { ... };// 结果:
// - 父组件渲染 → handleToggle 是新函数引用
// - TodoItem 的 props 变化(函数引用变了)
// - TodoItem 重新渲染(即使数据没变)
// - 所有 TodoItem 都会重新渲染!

使用 useCallback:

// ✅ 函数引用保持稳定
const handleToggle = useCallback((id: string) => { ... }, []);// 结果:
// - 父组件渲染 → handleToggle 是同一个函数引用
// - TodoItem 的 props 没变化(函数引用相同)
// - TodoItem 不重新渲染(memo 生效)
// - 只有数据真正变化的 TodoItem 才重新渲染!

总结

提示:这里对文章进行总结:

这些 Hooks 分别解决了函数组件的状态管理(useState)、副作用处理(useEffect)、DOM 操作 / 持久化数据(useRef)、计算结果缓存(useMemo)、函数缓存(useCallback)问题,是 React 函数组件开发的核心工具。

http://www.dtcms.com/a/580949.html

相关文章:

  • M|烟花 (1995)
  • 平顶山网站建设2022年黄台片区
  • 人工智能的未来之路:华为全栈技术链与AI Agent应用实践
  • 基于openresty反向代理、dns劫持、实现对http请求、响应内容抓包
  • 智能体的范式革命:华为全栈技术链驱动下一代AI Agent
  • AI 边缘计算:决胜未来
  • 【Linux】网络层协议
  • 深入解析 WPF 中的 DataTemplateSelector:动态模板选择的艺术
  • svn: E155000:
  • 【C++】:C++基于微服务的即时通讯系统(2)
  • Apple Pay 与 Google Pay 开发与结算全流程文档
  • Babylon.js相机交互:从 ArcRotateCamera 输入禁用说起
  • 安徽工程建设信息网站进皖企业wordpress优酷视频插件
  • git推送操作时报错error: failed to push some refs
  • 小程序弱网 / 无网场景下 CacheManager 离线表单与拍照上传解决方案
  • 邹平做网站公司一般的美工可以做网站吗
  • Vue3.4 Effect 作用域 API 与 React Server Components 实战解析
  • 基于改进TransUNet的港口船只图像分割系统研究
  • LeetCode 4. 寻找两个正序数组的中位数(困难)
  • 宇宙的几何诗篇:当空间本身成为运动的主角
  • Javascript函数之函数的基本使用以及封装?
  • 力扣 寻找两个正序数组的中位数
  • 文库类网站建设建议及经验上海高风险区域最新
  • 建设工程自学网站网站建设及管理使用情况汇报
  • Java 多线程同步机制深度解析:从 synchronized 到 Lock
  • AR眼镜在核电操作智能监护应用技术方案|阿法龙XR云平台
  • Rust 练习册 :Nth Prime与素数算法
  • 杭州网站建设机构win7做网站服务器卡
  • 算法基础篇:(三)基础算法之枚举:暴力美学的艺术,从穷举到高效优化
  • 【大模型学习3】预训练语言模型详解