免费

React Hooks 实战:打造高性能组件

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 最佳实践

  1. 只在顶层使用 Hooks(不要在循环、条件中)
  2. 只在 React 函数中使用 Hooks
  3. 使用 ESLint 插件(eslint-plugin-react-hooks)
  4. 合理拆分自定义 Hook,提升复用性
  5. 使用 useMemo 和 useCallback 优化性能

总结

React Hooks 让函数组件变得更加强大,是现代 React 开发的核心。掌握 Hooks 是每个 React 开发者的必备技能。