React Hooks最佳实践完全指南
React Hooks概述
Hooks是React 16.8引入的新特性,允许在函数组件中使用状态和其他React特性,无需编写类组件。
为什么使用Hooks
- 代码更简洁:无需class和this
- 逻辑复用:自定义Hook轻松共享逻辑
- 副作用分离:相关代码集中管理
- 更好的类型推断:TypeScript友好
基础Hooks
useState
import { useState } from 'react';
function Counter() {
// [当前状态, 更新函数]
const [count, setCount] = useState(0);
// 函数式更新(基于前一个状态)
const increment = () => setCount(prev => prev + 1);
// 惰性初始化(复杂初始值)
const [data, setData] = useState(() => {
const saved = localStorage.getItem('data');
return saved ? JSON.parse(saved) : defaultValue;
});
return (
Count: {count}
);
}
useEffect
import { useEffect, useState } from 'react';
function UserProfile({ userId }) {
const [user, setUser] = useState(null);
const [loading, setLoading] = useState(true);
// 组件挂载时执行
useEffect(() => {
console.log('Component mounted');
return () => {
console.log('Component unmounted');
};
}, []);
// 依赖变化时执行
useEffect(() => {
let cancelled = false;
async function fetchUser() {
setLoading(true);
const response = await fetch(`/api/users/${userId}`);
const data = await response.json();
if (!cancelled) {
setUser(data);
setLoading(false);
}
}
fetchUser();
// 清理函数
return () => {
cancelled = true;
};
}, [userId]); // 依赖数组
if (loading) return Loading...;
return {user?.name};
}
useContext
import { createContext, useContext, useState } from 'react';
// 创建Context
const ThemeContext = createContext('light');
const UserContext = createContext(null);
function App() {
const [theme, setTheme] = useState('dark');
const [user, setUser] = useState({ name: 'Alice' });
return (
);
}
function ThemeToggle() {
const { theme, setTheme } = useContext(ThemeContext);
return (
);
}
// 自定义Hook封装Context
function useTheme() {
const context = useContext(ThemeContext);
if (!context) {
throw new Error('useTheme must be used within ThemeProvider');
}
return context;
}
性能优化Hooks
useMemo和useCallback
import { useMemo, useCallback, useState } from 'react';
function ExpensiveComponent({ items, onItemClick }) {
// 缓存计算结果
const sortedItems = useMemo(() => {
console.log('Sorting items...');
return [...items].sort((a, b) => a.name.localeCompare(b.name));
}, [items]);
// 缓存回调函数
const handleClick = useCallback((id) => {
console.log('Item clicked:', id);
onItemClick(id);
}, [onItemClick]);
return (
-
{sortedItems.map(item => (
- ))}
React.memo
import { memo } from 'react';
// 浅比较props
const Item = memo(function Item({ item, onClick }) {
return (
自定义Hooks
useLocalStorage
function useLocalStorage(key, initialValue) {
const [storedValue, setStoredValue] = useState(() => {
try {
const item = localStorage.getItem(key);
return item ? JSON.parse(item) : initialValue;
} catch (error) {
console.error(error);
return initialValue;
}
});
const setValue = (value) => {
try {
const valueToStore = value instanceof Function
? value(storedValue)
: value;
setStoredValue(valueToStore);
localStorage.setItem(key, JSON.stringify(valueToStore));
} catch (error) {
console.error(error);
}
};
return [storedValue, setValue];
}
// 使用
const [name, setName] = useLocalStorage('name', 'Guest');
useFetch
function useFetch(url) {
const [data, setData] = useState(null);
const [loading, setLoading] = useState(true);
const [error, setError] = useState(null);
useEffect(() => {
let cancelled = false;
async function fetchData() {
setLoading(true);
try {
const response = await fetch(url);
if (!response.ok) throw new Error('Network error');
const json = await response.json();
if (!cancelled) {
setData(json);
setError(null);
}
} catch (e) {
if (!cancelled) setError(e);
} finally {
if (!cancelled) setLoading(false);
}
}
fetchData();
return () => { cancelled = true; };
}, [url]);
return { data, loading, error };
}
// 使用
function UserList() {
const { data: users, loading, error } = useFetch('/api/users');
if (loading) return Loading...;
if (error) return Error: {error.message};
return - {users.map(u =>
- {u.name} )}
进阶Hooks
useReducer
import { useReducer } from 'react';
const initialState = {
count: 0,
history: []
};
function reducer(state, action) {
switch (action.type) {
case 'increment':
return {
count: state.count + 1,
history: [...state.history, state.count]
};
case 'decrement':
return {
count: state.count - 1,
history: [...state.history, state.count]
};
case 'reset':
return initialState;
default:
throw new Error('Unknown action');
}
}
function Counter() {
const [state, dispatch] = useReducer(reducer, initialState);
return (
Count: {state.count}
);
}
useRef
import { useRef, useEffect } from 'react';
function TextInputWithFocus() {
const inputRef = useRef(null);
const renderCount = useRef(0);
useEffect(() => {
renderCount.current += 1;
});
const focusInput = () => {
inputRef.current?.focus();
};
return (
Renders: {renderCount.current}
);
}
最佳实践
- 遵循Hooks规则:只在顶层调用,不在循环/条件中
- 正确设置依赖:使用ESLint插件检查
- 合理拆分Effect:每个Effect做一件事
- 避免过度优化:不是所有函数都需要useCallback
- 抽象自定义Hook:复用逻辑,保持组件简洁
React Hooks让函数组件拥有了完整的能力,掌握它是现代React开发的必备技能。
本文链接:https://www.kkkliao.cn/?id=758 转载需授权!
版权声明:本文由廖万里的博客发布,如需转载请注明出处。



手机流量卡
免费领卡
号卡合伙人
产品服务
关于本站
