01. useEffect——管「额外的事」
React 组件主要负责「根据数据渲染 UI」,但有时候你需要干别的——发网络请求、订阅事件、操作 DOM、设置定时器。这些统统叫「副作用」,用 useEffect 来处理。
useEffect 接受一个函数和一个依赖数组。函数在组件渲染后执行;依赖数组告诉 React「这些值变了才重新执行」。空数组 [] 表示只在组件加载时跑一次。
jsx
import { useState, useEffect } from 'react';
function UserProfile({ userId }: { userId: number }) {
const [user, setUser] = useState(null);
useEffect(() => {
fetch(`/api/users/${userId}`)
.then(res => res.json())
.then(setUser);
}, [userId]); // userId 变了就重新拉数据
// 清理函数:组件卸载或依赖变化前执行
useEffect(() => {
const timer = setInterval(() => console.log('tick'), 1000);
return () => clearInterval(timer); // 一定要清理!
}, []);
if (!user) return <p>加载中...</p>;
return <div>{user.name}</div>;
}useEffect 的返回函数(清理函数)在组件卸载或者下一次 effect 执行前调用,用来清定时器、取消订阅等。忘记清理是内存泄漏的常见原因。
02. useRef——不被渲染影响的「小本本」
useRef 像一个「不被渲染影响的小本本」。它存的变量在组件整个生命周期里保持不变,改它的值也不会触发重新渲染。
主要用途:拿 DOM 元素的引用(比如自动聚焦输入框)、保存上一次的值、存任何不想触发重渲染的数据。
jsx
import { useRef, useEffect } from 'react';
function AutoFocusInput() {
const inputRef = useRef<HTMLInputElement>(null);
useEffect(() => { inputRef.current?.focus(); }, []);
return <input ref={inputRef} type="text" />;
}
// 保存上一次的值(经典自定义 Hook)
function usePrevious<T>(value: T): T | undefined {
const ref = useRef<T>();
useEffect(() => { ref.current = value; });
return ref.current;
}03. useMemo 和 useCallback——需要时才优化
当组件重新渲染时,里面的计算和函数都会重新创建。大部分时候这不是问题,但如果计算很重或者函数传给子组件导致不必要的重渲染,就需要优化。
useMemo——缓存计算结果,依赖不变就不重新算
useCallback——缓存函数引用,依赖不变就返回同一个函数
记住:不是每个地方都加这俩!只在真正需要优化的时候才用,否则反而增加复杂度和维护成本。
jsx
import { useMemo, useCallback } from 'react';
function ExpensiveList({ items, filter }: Props) {
// 只有 items 或 filter 变了才重新过滤
const filtered = useMemo(
() => items.filter(i => i.includes(filter)),
[items, filter]
);
// 函数引用不变,避免子组件不必要的重渲染
const handleClick = useCallback((id: number) => {
console.log('clicked', id);
}, []);
return filtered.map(item => <Item key={item} onClick={handleClick} />);
}04. 自定义 Hook——把逻辑抽出来复用
自定义 Hook 就是以 use 开头的普通函数,里面可以调用其他 Hook。这是 React 里复用状态逻辑的最佳方式——把「数据请求」「窗口尺寸」「表单处理」这些通用逻辑抽成自定义 Hook,多个组件直接用。
jsx
// 自定义 Hook:追踪窗口尺寸
function useWindowSize() {
const [size, setSize] = useState({
width: window.innerWidth,
height: window.innerHeight
});
useEffect(() => {
const handler = () => setSize({
width: window.innerWidth,
height: window.innerHeight
});
window.addEventListener('resize', handler);
return () => window.removeEventListener('resize', handler);
}, []);
return size;
}
// 在任何组件里直接用
function ResponsiveComponent() {
const { width } = useWindowSize();
return <p>窗口宽度:{width}px</p>;
}知识测验
第 1/5 题正确 0
useEffect 第二个参数是空数组 [] 代表什么?
下一节
下一节 状态管理