React Hooks 最佳实践:从入门到精通

深入探讨 React Hooks 的使用技巧和常见陷阱,帮助你写出更优雅的 React 代码

·8 分钟·更新于 2025/01/12·前端开发
#React#Hooks#JavaScript

React Hooks 最佳实践:从入门到精通

自从 React 16.8 引入 Hooks 以来,函数组件已经成为 React 开发的主流方式。但是,如何正确使用 Hooks 避免常见陷阱,仍然是很多开发者面临的挑战。

useState 的使用技巧

1. 避免在循环、条件或嵌套函数中调用 Hook

这是 React Hooks 的第一条规则。Hook 必须在组件的顶层调用,以确保每次渲染时 Hook 的调用顺序保持一致。

// ❌ 错误示例
function UserProfile({ userId }) {
  if (userId) {
    const [user, setUser] = useState(null) // 不要这样做!
  }
  return <div>...</div>
}
 
// ✅ 正确示例
function UserProfile({ userId }) {
  const [user, setUser] = useState(null)
  
  if (!userId) {
    return <div>请先登录</div>
  }
  
  return <div>...</div>
}

2. 使用函数式更新避免闭包陷阱

当新的 state 需要基于旧的 state 计算时,应该使用函数式更新。

// ❌ 可能出现问题
const [count, setCount] = useState(0)
 
const increment = () => {
  setCount(count + 1)
  setCount(count + 1) // 这里不会让 count 增加 2
}
 
// ✅ 推荐做法
const increment = () => {
  setCount(prev => prev + 1)
  setCount(prev => prev + 1) // 这样可以正确增加 2
}

useEffect 的深度应用

依赖数组的重要性

useEffect 的第二个参数是依赖数组,它决定了 effect 何时执行。

// ❌ 忘记添加依赖
useEffect(() => {
  fetchUser(userId) // userId 应该在依赖数组中
}, [])
 
// ✅ 正确添加依赖
useEffect(() => {
  fetchUser(userId)
}, [userId])

清理副作用

不要忘记清理副作用,特别是在处理订阅、定时器等场景时。

useEffect(() => {
  const timer = setInterval(() => {
    console.log('tick')
  }, 1000)
  
  // 返回清理函数
  return () => {
    clearInterval(timer)
  }
}, [])

自定义 Hook:代码复用的利器

自定义 Hook 是 React 最强大的特性之一。它允许你将组件逻辑提取到可重用的函数中。

// 自定义 Hook:useLocalStorage
function useLocalStorage(key, initialValue) {
  const [storedValue, setStoredValue] = useState(() => {
    try {
      const item = window.localStorage.getItem(key)
      return item ? JSON.parse(item) : initialValue
    } catch (error) {
      console.error(error)
      return initialValue
    }
  })
 
  const setValue = (value) => {
    try {
      setStoredValue(value)
      window.localStorage.setItem(key, JSON.stringify(value))
    } catch (error) {
      console.error(error)
    }
  }
 
  return [storedValue, setValue]
}
 
// 使用自定义 Hook
function App() {
  const [theme, setTheme] = useLocalStorage('theme', 'light')
  
  return (
    <div className={theme}>
      <button onClick={() => setTheme(theme === 'light' ? 'dark' : 'light')}>
        切换主题
      </button>
    </div>
  )
}

性能优化技巧

使用 useMemo 缓存计算结果

const expensiveValue = useMemo(() => {
  return computeExpensiveValue(a, b)
}, [a, b])

使用 useCallback 缓存函数

const handleClick = useCallback(() => {
  doSomething(a, b)
}, [a, b])

总结

React Hooks 为函数组件带来了强大的能力,但也需要我们遵循一些规则和最佳实践:

  1. 始终在顶层调用 Hook
  2. 正确使用依赖数组
  3. 记得清理副作用
  4. 善用自定义 Hook 实现代码复用
  5. 适时使用性能优化 Hook

掌握这些技巧,你就能写出更加优雅和高效的 React 代码。