React Hooks 是 React 16.8 引入的重大特性,它允许我们在不编写 class 的情况下使用 state 和其他 React 特性。本文将系统讲解 Hooks 的使用方法和最佳实践。
为什么需要 Hooks?
- 在组件之间复用状态逻辑很难(HOC、render props)
- 复杂组件变得难以理解,相关代码常分散
- class 组件难以理解,this 指向问题
- 难以理解 React 生命周期
基础 Hooks
useState
import { useState } from 'react'
function Counter() {
const [count, setCount] = useState(0)
return (
<div>
<p>你点击了 {count} 次</p>
<button onClick={() => setCount(count + 1)}>
点击
</button>
</div>
)
}
useEffect
import { useState, useEffect } from 'react'
function UserProfile({ userId }) {
const [user, setUser] = useState(null)
useEffect(() => {
fetchUser(userId).then(setUser)
}, [userId]) // 依赖数组
// 清理副作用
useEffect(() => {
const timer = setInterval(() => {
console.log('tick')
}, 1000)
return () => clearInterval(timer)
}, [])
return <div>{user?.name}</div>
}
useContext
const ThemeContext = React.createContext('light')
function App() {
return (
<ThemeContext.Provider value="dark">
<Toolbar />
</ThemeContext.Provider>
)
}
function Toolbar() {
const theme = useContext(ThemeContext)
return <div className={theme}>...</div>
}
额外的 Hooks
useReducer
适用于复杂的状态逻辑:
function reducer(state, action) {
switch (action.type) {
case 'increment':
return { count: state.count + 1 }
case 'decrement':
return { count: state.count - 1 }
default:
return state
}
}
function Counter() {
const [state, dispatch] = useReducer(reducer, { count: 0 })
return (
<>
Count: {state.count}
<button onClick={() => dispatch({type: 'increment'})}>+</button>
<button onClick={() => dispatch({type: 'decrement'})}>-</button>
</>
)
}
useMemo & useCallback
性能优化 Hook,避免不必要的重新计算:
function ExpensiveComponent({ items, onItemClick }) {
const sortedItems = useMemo(() => {
return [...items].sort((a, b) => a.name.localeCompare(b.name))
}, [items])
const handleClick = useCallback((id) => {
onItemClick(id)
}, [onItemClick])
return (
<ul>
{sortedItems.map(item => (
<li key={item.id} onClick={() => handleClick(item.id)}>
{item.name}
</li>
))}
</ul>
)
}
自定义 Hook
自定义 Hook 是 React 中复用状态逻辑的主要方式:
// useLocalStorage.js
import { useState, useEffect } from 'react'
export function useLocalStorage(key, initialValue) {
const [value, setValue] = useState(() => {
try {
const item = window.localStorage.getItem(key)
return item ? JSON.parse(item) : initialValue
} catch (error) {
return initialValue
}
})
useEffect(() => {
window.localStorage.setItem(key, JSON.stringify(value))
}, [key, value])
return [value, setValue]
}
// 使用
const [name, setName] = useLocalStorage('name', '智源论坛')
Hooks 最佳实践
- 只在顶层使用 Hooks(不要在循环、条件中)
- 只在 React 函数中使用 Hooks
- 使用 ESLint 插件(eslint-plugin-react-hooks)
- 合理拆分自定义 Hook,提升复用性
- 使用 useMemo 和 useCallback 优化性能
总结
React Hooks 让函数组件变得更加强大,是现代 React 开发的核心。掌握 Hooks 是每个 React 开发者的必备技能。