glownight

返回

为什么叫 Hook?#

核心区别#

普通函数提取React Hook
纯逻辑封装能”钩入”React内部机制
无状态能使用React状态和生命周期
独立运行必须在React组件上下文中运行

形象的”钩子”概念#

React组件

    ├─── useState ───→ 钩入React状态系统
    │                    (让函数能使用状态)

    ├─── useEffect ───→ 钩入React生命周期
    │                    (让函数能监听变化)

    └─── 自定义Hook ───→ 钩入React + 你的逻辑
                         (复用状态+逻辑的组合)
plaintext

关键区别详解#

1. 能使用React内置Hook#

// ❌ 普通函数 - 不能用useState
function normalFunction() {
  const [count, setCount] = useState(0); // ❌ 报错!
  return count;
}

// ✅ 自定义Hook - 能用useState
function useMyHook() {
  const [count, setCount] = useState(0); // ✅ 正常!
  return count;
}
javascript

2. 与React组件”绑定”#

// 普通函数 - 每次调用都是全新的
function getData() {
  return { value: Math.random() };
}

// 在组件中调用
function Component() {
  const data1 = getData(); // 值1
  const data2 = getData(); // 值2(不同)
}

// Hook - 与组件实例绑定
function useData() {
  const [value, setValue] = useState(Math.random());
  return value;
}

function Component() {
  const data1 = useData(); // 值1
  const data2 = useData(); // ❌ React会报错!
  // 因为Hook调用顺序必须一致
}
javascript

3. Hook的规则(为什么特殊)#

// Hook有严格的调用规则
function Component() {
  // ✅ 正确:在顶层调用
  const [a, setA] = useState(1);
  const [b, setB] = useState(2);
  
  if (condition) {
    // ❌ 错误:不能在条件语句中
    const [c, setC] = useState(3);
  }
  
  useEffect(() => {
    // 副作用逻辑
  }, []);
}
javascript

为什么有这些规则?

React通过调用顺序来识别Hook:

// React内部维护一个数组
const hooks = [
  { type: 'useState', value: 1 },      // 第一次调用 useState
  { type: 'useState', value: 2 },      // 第二次调用 useState  
  { type: 'useEffect', callback: fn }  // 第三次调用 useEffect
];

// 每次渲染按顺序匹配
// 如果顺序变了,React就混乱了
javascript

类比理解#

1. 钓鱼钩子 🎣#

// 普通函数 = 自己挖个池塘钓鱼
function normalFish() {
  return "鱼"; // 自己造的数据
}

// Hook = 在React这条大河里钓鱼
function useFish() {
  const [fish, setFish] = useState(null); // 钩入React的状态河流
  
  useEffect(() => {
    // 钩入React的生命周期
    fetchFish().then(setFish);
  }, []);
  
  return fish; // 从React河里钓上来的真鱼
}
javascript

2. 电源插座 🔌#

// 普通函数 = 独立的手电筒
function flashlight() {
  return "自带电池发光";
}

// Hook = 插入React电源插座
function useLight() {
  const [power, setPower] = useState(false); // 接入React电网
  
  useEffect(() => {
    // 插入插座后才能用电
    console.log("接入React电力系统");
  }, []);
  
  return power ? "💡亮" : "🔌灭";
}
javascript

3. 插件系统 🔌#

// React就像一个操作系统
// Hook就是系统的插件接口

// 普通函数 = 独立的程序
function calculator(a, b) {
  return a + b;
}

// Hook = 系统插件(能访问系统资源)
function useSystemPlugin() {
  const [memory, setMemory] = useState(0);  // 访问系统内存
  const [cpu, setCpu] = useState(0);        // 访问系统CPU
  
  useEffect(() => {
    // 监听系统事件
    subscribeToSystemEvents();
  }, []);
  
  return { memory, cpu };
}
javascript

实际代码对比#

普通工具函数#

// utils.js - 纯逻辑,与React无关
export function formatDate(date) {
  return date.toLocaleDateString();
}

export function calculateTotal(items) {
  return items.reduce((sum, item) => sum + item.price, 0);
}

// 任何地方都能用
formatDate(new Date());        // ✅
calculateTotal([{price: 10}]); // ✅
javascript

自定义Hook#

// useDate.js - 钩入React
import { useState, useEffect } from 'react';

export function useDate() {
  const [date, setDate] = useState(new Date());
  
  useEffect(() => {
    // 只有Hook才能用useEffect
    const timer = setInterval(() => setDate(new Date()), 1000);
    return () => clearInterval(timer);
  }, []);
  
  return date;
}

// 只能在组件或Hook中使用
function Component() {
  const date = useDate(); // ✅
}

formatDate(new Date()); // ❌ 不能在普通函数中用Hook
javascript

总结#

特性普通函数自定义Hook
调用环境任何地方只能在组件或Hook中
使用useState❌ 不行✅ 可以
使用useEffect❌ 不行✅ 可以
访问React生命周期❌ 不行✅ 可以
与组件实例绑定❌ 不绑定✅ 绑定
保持状态❌ 不保持✅ 保持
命名规范任意必须以use开头

一句话解释#

Hook = 能”钩入”React内部状态系统和生命周期的特殊函数

它不是简单的逻辑提取,而是React框架的扩展机制,让你的函数能获得React的超能力!

自定义hook什么叫"Hook"而不是简单的"函数提取"。
作者 glownight
发布于 2026年4月29日