React Hooks 的优势和使用场景

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

## 1. 代码复用性提升
通过自定义Hook可以轻松提取组件逻辑,使相同功能在不同组件间共享。传统高阶组件(HOC)和render props模式会导致组件树嵌套过深,而Hook直接在组件内部调用,保持组件扁平化。

```jsx
// 自定义Hook示例:获取窗口大小
function useWindowSize() {
  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;
}

// 在组件中使用
function MyComponent() {
  const { width } = useWindowSize();
  return <div>窗口宽度: {width}px</div>;
}

2. 逻辑关注点分离

类组件中相关逻辑分散在各个生命周期方法中,Hook允许按照功能而非生命周期来组织代码。相同功能的代码可以集中管理,提高可读性。

function UserProfile({ userId }) {
  // 用户数据相关逻辑
  const [user, setUser] = useState(null);
  useEffect(() => {
    fetchUser(userId).then(setUser);
  }, [userId]);

  // 用户活动相关逻辑
  const [activities, setActivities] = useState([]);
  useEffect(() => {
    fetchActivities(userId).then(setActivities);
  }, [userId]);

  // 渲染逻辑
  if (!user) return <Loading />;
  return (
    <div>
      <UserInfo user={user} />
      <ActivityList activities={activities} />
    </div>
  );
}

3. 简化复杂组件

使用useReducer可以替代Redux管理局部复杂状态,避免过度状态提升。

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

function TodoApp() {
  const [todos, dispatch] = useReducer(todosReducer, []);
  
  const handleAdd = text => {
    dispatch({ type: 'add', payload: { id: Date.now(), text } });
  };

  return (
    <>
      <TodoForm onSubmit={handleAdd} />
      <TodoList 
        todos={todos}
        onToggle={id => dispatch({ type: 'toggle', payload: id })}
      />
    </>
  );
}

4. 性能优化更精细

useMemo和useCallback可以精确控制重渲染和计算开销,避免不必要的性能损耗。

function ExpensiveComponent({ list, filter }) {
  const filteredList = useMemo(() => {
    return list.filter(item => item.includes(filter));
  }, [list, filter]); // 只有当list或filter变化时重新计算

  const handleClick = useCallback(() => {
    console.log('Item clicked');
  }, []); // 保持函数引用稳定

  return (
    <ul>
      {filteredList.map(item => (
        <li key={item} onClick={handleClick}>{item}</li>
      ))}
    </ul>
  );
}

5. 生命周期简化为副作用

useEffect统一处理副作用逻辑,替代componentDidMount、componentDidUpdate和componentWillUnmount。

function DataFetcher({ url }) {
  const [data, setData] = useState(null);
  const [error, setError] = useState(null);

  useEffect(() => {
    let isMounted = true;
    
    const fetchData = async () => {
      try {
        const result = await fetch(url);
        if (isMounted) setData(await result.json());
      } catch (err) {
        if (isMounted) setError(err);
      }
    };

    fetchData();

    return () => {
      isMounted = false; // 清理函数
    };
  }, [url]); // url变化时重新获取

  if (error) return <ErrorDisplay error={error} />;
  if (!data) return <Loading />;
  return <DataDisplay data={data} />;
}

6. 状态管理更灵活

useContext提供轻量级的状态共享方案,适合不需要Redux