React Hooks 的优势和使用场景

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

## 核心优势

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

```javascript
// 自定义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>Window width: {width}px</div>;
}

2. 代码组织更清晰

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

function UserProfile({ userId }) {
  // 状态管理集中
  const [user, setUser] = useState(null);
  const [loading, setLoading] = useState(false);
  
  // 副作用集中
  useEffect(() => {
    setLoading(true);
    fetchUser(userId).then(data => {
      setUser(data);
      setLoading(false);
    });
  }, [userId]);

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

3. 减少组件嵌套

避免为共享状态而创建多层嵌套组件:

// 使用Hook前
<ThemeProvider>
  <UserProvider>
    <Content />
  </UserProvider>
</ThemeProvider>

// 使用Hook后
function Content() {
  const theme = useTheme();
  const user = useUser();
  // 直接使用theme和user
}

主要使用场景

1. 状态管理

useState 适用于组件内部状态管理:

function Counter() {
  const [count, setCount] = useState(0);
  return (
    <button onClick={() => setCount(c => c + 1)}>
      Clicked {count} times
    </button>
  );
}

2. 副作用处理

useEffect 处理数据获取、订阅等副作用:

function DataFetcher({ url }) {
  const [data, setData] = useState(null);
  
  useEffect(() => {
    let ignore = false;
    fetch(url)
      .then(res => res.json())
      .then(data => !ignore && setData(data));
    
    return () => { ignore = true; };
  }, [url]);

  return <div>{JSON.stringify(data)}</div>;
}

3. 性能优化

useMemouseCallback 用于避免不必要的计算和渲染:

function ExpensiveComponent({ items, filter }) {
  const filteredItems = useMemo(() => {
    return items.filter(item => item.includes(filter));
  }, [items, filter]);

  const handleClick = useCallback(() => {
    console.log('Item clicked');
  }, []);

  return <List items={filteredItems} onClick={handleClick} />;
}

4. 访问上下文

useContext 简化上下文使用:

const ThemeContext = createContext('light');

function ThemedButton() {
  const theme = useContext(ThemeContext);
  return <button className={theme}>Click me</button>;
}

5. 引用DOM元素

useRef 用于访问DOM节点或保存可变值:

function TextInput() {
  const inputRef = useRef(null);
  
  const focusInput = () => {
    inputRef.current.focus();
  };

  return (
    <>
      <input ref={inputRef} />
      <button onClick={focusInput}>Focus</button>
    </>
  );
}

最佳实践

  1. 只在顶层调用Hook:不要在循环、条件或嵌套函数中调用Hook
  2. 按逻辑分组:将相关的state和effect放在一起
  3. 合理使用依赖数组:确保useEffect依赖项完整
  4. 自定义Hook命名:以use开头命名自定义Hook
  5. 适度拆分:当组件逻辑复杂时,拆分为多个自定义Hook

注意事项

  1. 不要滥用useEffect:避免在useEffect中做太多事情
  2. 性能敏感场景:对于高频更新使用useReducer而非useState
  3. 复杂状态逻辑:当state相互依赖时