React Hooks

React Hooks 是 React 16.8 引入的功能,允许函数组件使用状态(state)、生命周期等特性,无需编写类组件。Hooks 使代码更简洁、可复用,并提升了函数组件的灵活性。以下是对 React Hooks 的中文讲解,涵盖核心概念、常用 Hooks、用法示例和注意事项,力求简洁清晰。


1. 什么是 React Hooks?

Hooks 是特殊的函数,允许在函数组件中“钩入” React 的状态管理和生命周期功能。主要目标:

  • 取代类组件的复杂逻辑(如 setStatecomponentDidMount)。
  • 提高代码复用性,避免高阶组件(HOC)或渲染属性(render props)的嵌套。
  • 使函数组件更强大,逻辑更清晰。

注意:Hooks 仅适用于函数组件和自定义 Hooks,不支持类组件。


2. 常用内置 Hooks

React 提供了一系列内置 Hooks,以下是常用的核心 Hooks:

1. useState

管理组件状态,替代类组件的 this.statethis.setState

示例
import { useState } from 'react';

function Counter() {
  const [count, setCount] = useState(0); // 初始值为 0

  return (
    <div>
      <p>计数: {count}</p>
      <button onClick={() => setCount(count + 1)}>加 1</button>
    </div>
  );
}
  • 说明
  • useState 返回状态值(count)和更新函数(setCount)。
  • 更新状态时,setCount 可接收新值或函数(如 setCount(prev => prev + 1))。
  • 用途:管理简单状态,如计数器、表单输入等。

2. useEffect

处理副作用(如数据获取、订阅、DOM 操作),替代类组件的生命周期方法(componentDidMountcomponentDidUpdatecomponentWillUnmount)。

示例
import { useState, useEffect } from 'react';

function DataFetcher() {
  const [data, setData] = useState(null);

  useEffect(() => {
    fetch('https://api.example.com/data')
      .then(res => res.json())
      .then(setData);

    // 清理函数(可选)
    return () => console.log('清理副作用');
  }, []); // 空依赖数组,类似 componentDidMount

  return <div>{data ? data.name : '加载中...'}</div>;
}
  • 说明
  • useEffect 接受两个参数:副作用函数和依赖数组。
  • 依赖数组([])控制副作用执行时机:
    • 空数组([]):仅在挂载时执行一次。
    • 含变量(如 [count]):变量变化时执行。
    • 无依赖数组:每次渲染都执行。
  • 返回清理函数(可选),在组件卸载或依赖变化前执行。
  • 用途:数据获取、事件监听、定时器等。

3. useContext

访问 React Context,简化跨组件传递数据。

示例
import { createContext, useContext } from 'react';

const ThemeContext = createContext('light');

function ThemeComponent() {
  const theme = useContext(ThemeContext);
  return <div>当前主题: {theme}</div>;
}

function App() {
  return (
    <ThemeContext.Provider value="dark">
      <ThemeComponent />
    </ThemeContext.Provider>
  );
}
  • 说明useContext 获取最近的 Provider 提供的 value
  • 用途:主题切换、全局用户状态等。

4. useReducer

管理复杂状态逻辑,类似 Redux 的 reducer,适合替代 useState 处理复杂状态更新。

示例
import { useReducer } from 'react';

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

function Counter() {
  const [state, dispatch] = useReducer(reducer, { count: 0 });

  return (
    <div>
      <p>计数: {state.count}</p>
      <button onClick={() => dispatch({ type: 'increment' })}>加 1</button>
      <button onClick={() => dispatch({ type: 'decrement' })}>减 1</button>
    </div>
  );
}
  • 说明useReducer 返回状态和 dispatch 函数,通过 action 更新状态。
  • 用途:复杂状态管理,如表单、多状态交互。

5. useCallbackuseMemo

优化性能,防止不必要的函数或值重新创建。

useCallback 示例
import { useState, useCallback } from 'react';

function Child({ onClick }) {
  console.log('Child 渲染');
  return <button onClick={onClick}>子组件按钮</button>;
}

function Parent() {
  const [count, setCount] = useState(0);
  const handleClick = useCallback(() => console.log('点击'), []); // 缓存函数

  return (
    <div>
      <button onClick={() => setCount(count + 1)}>计数: {count}</button>
      <Child onClick={handleClick} />
    </div>
  );
}
  • 说明useCallback 缓存函数引用,防止子组件因函数重新创建而重新渲染。
  • 用途:传递给 React.memo 包裹的子组件。
useMemo 示例
import { useMemo, useState } from 'react';

function ExpensiveComponent({ numbers }) {
  const sum = useMemo(() => {
    console.log('计算总和');
    return numbers.reduce((a, b) => a + b, 0);
  }, [numbers]);

  return <div>总和: {sum}</div>;
}
  • 说明useMemo 缓存计算结果,仅在依赖变化时重新计算。
  • 用途:昂贵计算、复杂对象生成。

6. useRef

创建可变引用对象,常用于访问 DOM 或保存值(不触发重新渲染)。

示例
import { useRef } from 'react';

function InputFocus() {
  const inputRef = useRef(null);

  const focusInput = () => {
    inputRef.current.focus();
  };

  return (
    <div>
      <input ref={inputRef} />
      <button onClick={focusInput}>聚焦输入框</button>
    </div>
  );
}
  • 说明useRef.current 属性保存引用,值变化不触发渲染。
  • 用途:DOM 操作、保存上一次状态、定时器 ID 等。

7. useNavigate(React Router)

用于编程式导航,来自 react-router-dom

示例
import { useNavigate } from 'react-router-dom';

function LoginButton() {
  const navigate = useNavigate();

  return (
    <button onClick={() => navigate('/dashboard')}>
      跳转到仪表盘
    </button>
  );
}
  • 说明useNavigate 返回导航函数,支持跳转、历史记录操作。
  • 用途:动态路由跳转。

3. 自定义 Hooks

将逻辑封装为可复用函数,名称以 use 开头。

示例
import { useState, useEffect } from 'react';

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 App() {
  const { width, height } = useWindowSize();
  return <div>窗口大小: {width} x {height}</div>;
}
  • 说明:自定义 Hooks 封装状态和副作用逻辑,可在多个组件复用。
  • 用途:表单处理、数据获取、动画等。

4. Hooks 规则

React 对 Hooks 使用有严格规则:

  1. 仅在顶层调用:不要在循环、条件或嵌套函数中调用 Hooks。
  2. 仅在函数组件或自定义 Hooks 中调用:不要在普通函数或类组件中使用。
  3. 使用 ESLint 插件(如 eslint-plugin-react-hooks)检查规则合规性。
示例(错误用法)
function App() {
  if (true) {
    const [count, setCount] = useState(0); // 错误:在条件中调用
  }
}

5. 与 React Router 结合

Hooks 常与 react-router-dom 结合,用于导航、参数获取等:

  • useParams:获取动态路由参数(如 /users/:id)。
  • useLocation:获取当前 URL 信息。
  • useNavigate:编程式导航。
示例
import { useParams, useNavigate } from 'react-router-dom';

function UserProfile() {
  const { id } = useParams(); // 获取 :id 参数
  const navigate = useNavigate();

  return (
    <div>
      <h1>用户 ID: {id}</h1>
      <button onClick={() => navigate('/')}>返回首页</button>
    </div>
  );
}

6. 注意事项

  1. 性能优化
  • 使用 useCallbackuseMemo 避免不必要的重新渲染。
  • 谨慎使用 useEffect,确保依赖数组正确,避免无限循环。
  1. 调试
  • 使用 React Developer Tools 检查 Hooks 状态。
  • 打印依赖数组变化,排查副作用问题。
  1. 学习曲线
  • 熟悉 useEffect 的依赖管理是关键。
  • 自定义 Hooks 需要清晰的逻辑封装。
  1. 与类组件对比
  • Hooks 代码更简洁,但逻辑分散可能增加维护成本。
  • 类组件仍适用于某些场景(如复杂生命周期逻辑)。

7. 选择建议

  • 简单状态:使用 useState
  • 复杂状态:使用 useReducer
  • 副作用:使用 useEffect
  • 性能优化:结合 useCallbackuseMemoReact.memo
  • 全局数据:使用 useContext
  • 可复用逻辑:编写自定义 Hooks。

8. 资源

  • React 官方文档:https://react.dev/learn#using-hooks
  • Hooks API:https://react.dev/reference/react
  • 中文社区:搜索“React Hooks 中文教程”或参考掘金、知乎。

如果需要更详细的某 Hook 讲解(如 useEffect 高级用法或自定义 Hooks 案例),请告诉我!

类似文章

发表回复

您的邮箱地址不会被公开。 必填项已用 * 标注