# 01-React Hooks核心
## 📋 学习目标
- 掌握常用Hooks的使用
- 理解Hooks的原理和规则
- 学习自定义Hook开发
- 掌握性能优化Hooks
## 🪝 useState
### 基本用法
```jsx
import {useState} from 'react';
function Counter() {
const [count, setCount] = useState(0);
return (
Count: {count}
);
}
// 初始值可以是函数
function ExpensiveComponent() {
const [data, setData] = useState(() => {
return computeExpensiveValue();
});
}
```
### 对象和数组状态
```jsx
function Form() {
const [user, setUser] = useState({
name: '',
age: 0
});
// 更新对象(需要创建新对象)
const updateName = (name) => {
setUser({...user, name});
// 或
setUser(prev => ({...prev, name}));
};
// 数组状态
const [items, setItems] = useState([]);
const addItem = (item) => {
setItems([...items, item]);
};
const removeItem = (index) => {
setItems(items.filter((_, i) => i !== index));
};
}
```
## 🎬 useEffect
### 基本用法
```jsx
import {useEffect} from 'react';
function Component() {
// 每次渲染都执行
useEffect(() => {
console.log('Rendered');
});
// 仅首次渲染执行
useEffect(() => {
console.log('Mounted');
}, []);
// 依赖变化时执行
useEffect(() => {
console.log('Count changed:', count);
}, [count]);
// 清理函数
useEffect(() => {
const timer = setInterval(() => {
console.log('Tick');
}, 1000);
return () => {
clearInterval(timer);
};
}, []);
}
```
### 实际应用
```jsx
// 数据获取
function UserProfile({userId}) {
const [user, setUser] = useState(null);
const [loading, setLoading] = useState(true);
useEffect(() => {
let isCancelled = false;
async function fetchUser() {
setLoading(true);
try {
const response = await fetch(`/api/users/${userId}`);
const data = await response.json();
if (!isCancelled) {
setUser(data);
}
} catch (error) {
console.error(error);
} finally {
if (!isCancelled) {
setLoading(false);
}
}
}
fetchUser();
return () => {
isCancelled = true;
};
}, [userId]);
if (loading) return Loading...
;
return {user?.name}
;
}
// 订阅事件
function WindowSize() {
const [size, setSize] = useState({
width: window.innerWidth,
height: window.innerHeight
});
useEffect(() => {
const handleResize = () => {
setSize({
width: window.innerWidth,
height: window.innerHeight
});
};
window.addEventListener('resize', handleResize);
return () => {
window.removeEventListener('resize', handleResize);
};
}, []);
return {size.width} x {size.height}
;
}
```
## 🎯 useContext
### 基本用法
```jsx
import {createContext, useContext} from 'react';
// 创建Context
const ThemeContext = createContext('light');
// Provider
function App() {
return (
);
}
// 使用Context
function Toolbar() {
const theme = useContext(ThemeContext);
return Toolbar
;
}
// 复杂Context
const UserContext = createContext(null);
export function UserProvider({children}) {
const [user, setUser] = useState(null);
const login = async (credentials) => {
const userData = await api.login(credentials);
setUser(userData);
};
const logout = () => {
setUser(null);
};
return (
{children}
);
}
export function useUser() {
const context = useContext(UserContext);
if (!context) {
throw new Error('useUser must be used within UserProvider');
}
return context;
}
```
## 🔄 useReducer
### 基本用法
```jsx
import {useReducer} from 'react';
// Reducer函数
function counterReducer(state, action) {
switch (action.type) {
case 'increment':
return {count: state.count + 1};
case 'decrement':
return {count: state.count - 1};
case 'reset':
return {count: 0};
default:
throw new Error('Unknown action type');
}
}
function Counter() {
const [state, dispatch] = useReducer(counterReducer, {count: 0});
return (
Count: {state.count}
);
}
// TypeScript版本
type State = {count: number};
type Action =
| {type: 'increment'}
| {type: 'decrement'}
| {type: 'reset'};
function counterReducer(state: State, action: Action): State {
// ...
}
```
### 复杂表单管理
```jsx
function formReducer(state, action) {
switch (action.type) {
case 'UPDATE_FIELD':
return {
...state,
[action.field]: action.value
};
case 'RESET':
return action.initialState;
default:
return state;
}
}
function Form() {
const initialState = {
name: '',
email: '',
message: ''
};
const [formData, dispatch] = useReducer(formReducer, initialState);
const handleChange = (field) => (e) => {
dispatch({
type: 'UPDATE_FIELD',
field,
value: e.target.value
});
};
return (
);
}
```
## 📌 useRef
### 基本用法
```jsx
import {useRef, useEffect} from 'react';
function Input() {
const inputRef = useRef(null);
useEffect(() => {
// 自动聚焦
inputRef.current.focus();
}, []);
return ;
}
// 存储可变值(不触发重渲染)
function Timer() {
const intervalRef = useRef(null);
const [count, setCount] = useState(0);
const start = () => {
if (intervalRef.current) return;
intervalRef.current = setInterval(() => {
setCount(c => c + 1);
}, 1000);
};
const stop = () => {
if (intervalRef.current) {
clearInterval(intervalRef.current);
intervalRef.current = null;
}
};
useEffect(() => {
return () => stop();
}, []);
return (
);
}
```
## ⚡ useMemo
### 基本用法
```jsx
import {useMemo} from 'react';
function ExpensiveComponent({items}) {
// 缓存计算结果
const total = useMemo(() => {
console.log('Computing total...');
return items.reduce((sum, item) => sum + item.price, 0);
}, [items]);
return Total: ${total}
;
}
// 缓存对象引用
function Parent() {
const [count, setCount] = useState(0);
// 每次渲染都会创建新对象
// const config = {theme: 'dark'};
// 使用useMemo缓存
const config = useMemo(() => ({theme: 'dark'}), []);
return ;
}
const Child = React.memo(({config}) => {
console.log('Child rendered');
return {config.theme}
;
});
```
## 🔄 useCallback
### 基本用法
```jsx
import {useCallback} from 'react';
function Parent() {
const [count, setCount] = useState(0);
// 每次渲染都创建新函数
// const handleClick = () => setCount(c => c + 1);
// 缓存函数
const handleClick = useCallback(() => {
setCount(c => c + 1);
}, []);
return ;
}
const Child = React.memo(({onClick}) => {
console.log('Child rendered');
return ;
});
// 实际应用
function SearchInput({onSearch}) {
const [query, setQuery] = useState('');
// 防抖搜索
const debouncedSearch = useCallback(
debounce((value) => {
onSearch(value);
}, 500),
[onSearch]
);
const handleChange = (e) => {
const value = e.target.value;
setQuery(value);
debouncedSearch(value);
};
return ;
}
```
## 🛠️ 自定义Hook
### 基本自定义Hook
```jsx
// useLocalStorage
function useLocalStorage(key, initialValue) {
const [value, setValue] = useState(() => {
const item = localStorage.getItem(key);
return item ? JSON.parse(item) : initialValue;
});
const setStoredValue = (newValue) => {
setValue(newValue);
localStorage.setItem(key, JSON.stringify(newValue));
};
return [value, setStoredValue];
}
// 使用
function App() {
const [name, setName] = useLocalStorage('name', '');
return setName(e.target.value)} />;
}
// useFetch
function useFetch(url) {
const [data, setData] = useState(null);
const [loading, setLoading] = useState(true);
const [error, setError] = useState(null);
useEffect(() => {
let isCancelled = false;
async function fetchData() {
try {
const response = await fetch(url);
const json = await response.json();
if (!isCancelled) {
setData(json);
setError(null);
}
} catch (err) {
if (!isCancelled) {
setError(err);
}
} finally {
if (!isCancelled) {
setLoading(false);
}
}
}
fetchData();
return () => {
isCancelled = true;
};
}, [url]);
return {data, loading, error};
}
// 使用
function UserList() {
const {data, loading, error} = useFetch('/api/users');
if (loading) return Loading...
;
if (error) return Error: {error.message}
;
return (
{data.map(user => (
- {user.name}
))}
);
}
```
### 高级自定义Hook
```jsx
// useDebounce
function useDebounce(value, delay) {
const [debouncedValue, setDebouncedValue] = useState(value);
useEffect(() => {
const timer = setTimeout(() => {
setDebouncedValue(value);
}, delay);
return () => clearTimeout(timer);
}, [value, delay]);
return debouncedValue;
}
// useInterval
function useInterval(callback, delay) {
const savedCallback = useRef();
useEffect(() => {
savedCallback.current = callback;
}, [callback]);
useEffect(() => {
if (delay === null) return;
const tick = () => savedCallback.current();
const id = setInterval(tick, delay);
return () => clearInterval(id);
}, [delay]);
}
// usePrevious
function usePrevious(value) {
const ref = useRef();
useEffect(() => {
ref.current = value;
}, [value]);
return ref.current;
}
```
## 📏 Hooks规则
### 两大规则
```jsx
// ✅ 规则1:只在顶层调用Hook
function Component() {
const [count, setCount] = useState(0);
// ❌ 不要在条件语句中调用
if (count > 0) {
// const [name, setName] = useState('');
}
// ❌ 不要在循环中调用
for (let i = 0; i < 10; i++) {
// const [item, setItem] = useState(i);
}
}
// ✅ 规则2:只在React函数中调用Hook
function Component() {
const [count, setCount] = useState(0); // ✅
}
function useCustomHook() {
const [value, setValue] = useState(0); // ✅
}
// ❌ 不要在普通函数中调用
function normalFunction() {
// const [value, setValue] = useState(0);
}
```
## 📚 实践练习
### 练习1:自定义Hook
实现以下自定义Hook:
- useToggle:布尔值切换
- useArray:数组操作
- useAsync:异步操作
### 练习2:表单管理
使用useReducer实现表单管理:
- 字段验证
- 错误提示
- 提交处理
### 练习3:性能优化
优化以下组件:
- 大列表渲染
- 复杂计算
- 频繁更新
## 📚 参考资料
- [React Hooks官方文档](https://react.dev/reference/react)
- [usehooks.com](https://usehooks.com/)
- [React Hooks Cheatsheet](https://react-hooks-cheatsheet.com/)