React Hooks 的优势和使用场景

30 阅读2分钟
# React Hooks 的优势和使用场景

## 1. Hooks 的核心优势

### 1.1 逻辑复用更简单
通过自定义 Hook 可以提取组件逻辑,使状态逻辑复用变得简单。相比 HOC 和 Render Props 模式,Hook 不会产生嵌套地狱。

```jsx
// 自定义计数器 Hook
function useCounter(initialValue) {
  const [count, setCount] = useState(initialValue);
  const increment = () => setCount(c => c + 1);
  return { count, increment };
}

// 组件中使用
function MyComponent() {
  const { count, increment } = useCounter(0);
  return <button onClick={increment}>{count}</button>;
}

1.2 代码组织更清晰

相关逻辑可以集中在一起,而不是分散在各个生命周期方法中。

function UserProfile({ userId }) {
  // 状态管理集中
  const [user, setUser] = useState(null);
  const [loading, setLoading] = useState(false);
  
  // 副作用集中
  useEffect(() => {
    const fetchUser = async () => {
      setLoading(true);
      const response = await fetch(`/users/${userId}`);
      setUser(await response.json());
      setLoading(false);
    };
    fetchUser();
  }, [userId]);

  if (loading) return <Spinner />;
  return <Profile user={user} />;
}

1.3 减少组件嵌套

不再需要为了复用状态逻辑而创建包装组件,减少了组件树的嵌套层级。

2. 常用 Hooks 使用场景

2.1 useState - 状态管理

适用于组件内部的状态管理,替代类组件的 this.state。

function Counter() {
  const [count, setCount] = useState(0);
  return (
    <div>
      <p>You clicked {count} times</p>
      <button onClick={() => setCount(count + 1)}>
        Click me
      </button>
    </div>
  );
}

2.2 useEffect - 副作用处理

处理数据获取、订阅、手动修改 DOM 等副作用操作,可以替代 componentDidMount、componentDidUpdate 和 componentWillUnmount。

function WindowWidth() {
  const [width, setWidth] = useState(window.innerWidth);
  
  useEffect(() => {
    const handleResize = () => setWidth(window.innerWidth);
    window.addEventListener('resize', handleResize);
    return () => window.removeEventListener('resize', handleResize);
  }, []);

  return <div>Window width: {width}</div>;
}

2.3 useContext - 跨组件共享状态

无需组件层层传递 props 就能共享全局状态。

const ThemeContext = React.createContext('light');

function App() {
  return (
    <ThemeContext.Provider value="dark">
      <Toolbar />
    </ThemeContext.Provider>
  );
}

function Toolbar() {
  const theme = useContext(ThemeContext);
  return <div style={{ background: theme === 'dark' ? '#333' : '#FFF' }}>
    Current theme: {theme}
  </div>;
}

2.4 useReducer - 复杂状态逻辑

适合管理包含多个子值的复杂 state 逻辑,或者下一个 state 依赖于之前的 state。

function todosReducer(state, action) {
  switch (action.type) {
    case 'add':
      return [...state, { text: action.text, completed: false }];
    case 'toggle':
      return state.map((todo, i) => 
        i === action.index ? {...todo, completed: !todo.completed} : todo
      );
    default:
      return state;
  }
}

function TodoList() {
  const [todos, dispatch] = useReducer(todosReducer, []);
  
  function handleAdd(text) {
    dispatch({ type: 'add', text });
  }
  
  // ...
}

2.5 useMemo/useCallback - 性能优化

用于优化计算开销大的操作和避免不必要的子组件重新渲染。

function Parent({ a, b }) {
  // 只有 a 变化时才会重新计算
  const memoizedValue = useMemo(() => computeExpensiveValue(a), [a]);
  
  // 只有 b 变化时才会重新创建函数
  const memoizedCallback = useCallback(() => doSomething(b), [b]);
  
  return <Child callback={memoizedCallback} />;
}

3. 使用 Hooks 的最佳实践

  1. **只在顶层调用 Hook