React Hooks 的优势和使用场景

36 阅读1分钟
# React Hooks 的优势和使用场景

## 核心优势

### 1. 逻辑复用更简单
通过自定义 Hook 可以轻松复用状态逻辑,避免了高阶组件和 render props 的嵌套问题。

```jsx
// 自定义 Hook 示例
function useWindowWidth() {
  const [width, setWidth] = useState(window.innerWidth);
  
  useEffect(() => {
    const handleResize = () => setWidth(window.innerWidth);
    window.addEventListener('resize', handleResize);
    return () => window.removeEventListener('resize', handleResize);
  }, []);

  return width;
}

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

2. 代码更简洁

消除了 class 组件的繁琐写法,函数组件可以完成所有功能。

// 类组件 vs 函数组件+Hooks
class Example extends React.Component {
  state = { count: 0 };
  
  componentDidMount() {
    document.title = `点击了 ${this.state.count} 次`;
  }
  
  componentDidUpdate() {
    document.title = `点击了 ${this.state.count} 次`;
  }

  render() {
    return (
      <button onClick={() => this.setState({ count: this.state.count + 1 })}>
        点击 {this.state.count} 次
      </button>
    );
  }
}

// 使用 Hooks
function Example() {
  const [count, setCount] = useState(0);
  
  useEffect(() => {
    document.title = `点击了 ${count} 次`;
  }, [count]);

  return (
    <button onClick={() => setCount(count + 1)}>
      点击 {count} 次
    </button>
  );
}

3. 更好的关注点分离

通过多个 useEffect 可以将相关逻辑组织在一起,而不是分散在不同的生命周期方法中。

function FriendStatus({ friendId }) {
  const [status, setStatus] = useState(null);

  // 订阅好友状态
  useEffect(() => {
    const handleStatusChange = (status) => setStatus(status);
    ChatAPI.subscribe(friendId, handleStatusChange);
    return () => ChatAPI.unsubscribe(friendId, handleStatusChange);
  }, [friendId]);

  // 更新文档标题
  useEffect(() => {
    document.title = `好友 ${friendId} 的状态: ${status}`;
  }, [status, friendId]);

  return <div>好友状态: {status}</div>;
}

主要使用场景

1. 状态管理

useState 适用于简单的组件状态管理:

function Counter() {
  const [count, setCount] = useState(0);
  const [step, setStep] = useState(1);

  return (
    <>
      <button onClick={() => setCount(c => c + step)}>
        增加 {step}
      </button>
      <input 
        type="number" 
        value={step}
        onChange={e => setStep(Number(e.target.value))}
      />
      当前值: {count}
    </>
  );
}

2. 副作用处理

useEffect 适用于数据获取、订阅、手动 DOM 操作等副作用:

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

  useEffect(() => {
    const fetchData = async () => {
      try {
        setLoading(true);
        const response = await fetch(url);
        const result = await response.json();
        setData(result);
      } catch (err) {
        setError(err);
      } finally {
        setLoading(false);
      }
    };

    fetchData();
  }, [url]);

  if (loading) return <div>加载中...</div>;
  if (error) return <div>错误: {error.message}</div>;
  return <pre>{JSON.stringify(data, null, 2)}</pre>;
}

3. 性能优化

useMemouseCallback 可以优化性能,避免不必要的计算和渲染:

function ExpensiveComponent({ list, filter }) {
  const filteredList = useMemo(() => {
    console.log('重新计算过滤列表');
    return list.filter(item => item.includes(filter));
  }, [list, filter]);

  const handleClick = useCallback(() => {
    console.log('点击处理', filter);
  }, [filter]);