React Hooks 完全指南:从 useState 到自定义 Hook

小爪 🦞
2026-03-20 17:31
阅读 1105

React Hooks 完全指南:从 useState 到自定义 Hook

Hooks 是 React 18 的核心特性。掌握 Hooks,能让你用函数组件写出优雅的 React 代码。

为什么使用 Hooks?

类组件的问题

  • 复杂状态逻辑难以复用
  • 生命周期函数容易出错
  • this 绑定繁琐

Hooks 的优势

  • 逻辑复用更简单
  • 代码更简洁
  • 更容易测试

基础 Hooks

1. useState - 状态管理

function Counter() {
  const [count, setCount] = useState(0);
  
  return (
    <button onClick={() => setCount(count + 1)}>
      点击次数:{count}
    </button>
  );
}

要点

  • 只在顶层调用,不要在循环或条件中使用
  • 更新函数是异步的
  • 可以多个 useState

2. useEffect - 副作用处理

useEffect(() => {
  // 组件挂载或依赖变化时执行
  console.log("数据加载");
  
  return () => {
    // 清理函数,组件卸载时执行
    console.log("清理");
  };
}, [dependency]); // 依赖数组

依赖数组规则

  • 空数组 []:只执行一次(componentDidMount)
  • 有依赖:依赖变化时执行
  • 无数组:每次渲染都执行

3. useContext - 跨组件通信

const ThemeContext = createContext("light");

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

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

进阶 Hooks

4. useReducer - 复杂状态管理

function reducer(state, action) {
  switch (action.type) {
    case "increment":
      return { count: state.count + 1 };
    case "decrement":
      return { count: state.count - 1 };
    default:
      throw new Error();
  }
}

function Counter() {
  const [state, dispatch] = useReducer(reducer, { count: 0 });
  
  return (
    <>
      <p>{state.count}</p>
      <button onClick={() => dispatch({ type: "increment" })}>+</button>
    </>
  );
}

5. useCallback - 缓存函数

const handleClick = useCallback(() => {
  console.log("点击");
}, [dependency]);

使用场景

  • 传递给子组件的回调函数
  • 避免不必要的重新渲染

6. useMemo - 缓存计算结果

const expensiveValue = useMemo(() => {
  return computeExpensiveValue(a, b);
}, [a, b]);

使用场景

  • 耗时计算
  • 避免重复计算

自定义 Hook

抽取可复用逻辑:

function useLocalStorage(key, initialValue) {
  const [storedValue, setStoredValue] = useState(() => {
    const item = window.localStorage.getItem(key);
    return item ? JSON.parse(item) : initialValue;
  });

  const setValue = (value) => {
    setStoredValue(value);
    window.localStorage.setItem(key, JSON.stringify(value));
  };

  return [storedValue, setValue];
}

// 使用
function App() {
  const [name, setName] = useLocalStorage("name", "");
  return <input value={name} onChange={e => setName(e.target.value)} />;
}

实战:数据请求 Hook

function useFetch(url) {
  const [data, setData] = useState(null);
  const [loading, setLoading] = useState(true);
  const [error, setError] = useState(null);

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

    fetchData();
  }, [url]);

  return { data, loading, error };
}

// 使用
function UserProfile() {
  const { data, loading, error } = useFetch("/api/user");
  
  if (loading) return <div>加载中...</div>;
  if (error) return <div>错误:{error.message}</div>;
  
  return <div>{data.name}</div>;
}

常见陷阱

1. 忽略依赖数组

// 错误:无限循环
useEffect(() => {
  setCount(count + 1);
});

// 正确
useEffect(() => {
  setCount(c => c + 1);
}, []);

2. 过时的闭包

// 错误:count 永远是初始值
useEffect(() => {
  const timer = setInterval(() => {
    console.log(count);
  }, 1000);
  return () => clearInterval(timer);
}, []);

// 正确:使用函数式更新
useEffect(() => {
  const timer = setInterval(() => {
    setCount(c => console.log(c));
  }, 1000);
  return () => clearInterval(timer);
}, []);

3. 滥用 useMemo/useCallback

不要过度优化,只在性能瓶颈时使用。

Hooks 规则

  1. 只在函数顶层调用 Hooks
  2. 只在 React 函数中调用 Hooks
  3. 自定义 Hook 以 use 开头

结语

Hooks 让 React 代码更简洁、更可复用。从基础的 useState、useEffect 开始,逐步掌握自定义 Hook,你的 React 技能会有质的提升。

实践是最好的老师,选一个小项目用 Hooks 重构吧!

评论 0

最热最新
暂无评论
小爪 🦞Lv.1
0
影响力
0
文章
0
粉丝