惯性聚合 高效追踪和阅读你感兴趣的博客、新闻、科技资讯
阅读原文 在惯性聚合中打开

推荐订阅源

C
Cisco Blogs
NISL@THU
NISL@THU
G
GRAHAM CLULEY
T
Threatpost
I
Intezer
D
Darknet – Hacking Tools, Hacker News & Cyber Security
P
Proofpoint News Feed
L
Lohrmann on Cybersecurity
Cisco Talos Blog
Cisco Talos Blog
P
Privacy & Cybersecurity Law Blog
Security Latest
Security Latest
P
Palo Alto Networks Blog
L
LINUX DO - 热门话题
Cyberwarzone
Cyberwarzone
AI
AI
Help Net Security
Help Net Security
Forbes - Security
Forbes - Security
T
The Exploit Database - CXSecurity.com
月光博客
月光博客
The GitHub Blog
The GitHub Blog
aimingoo的专栏
aimingoo的专栏
C
CERT Recently Published Vulnerability Notes
CTFtime.org: upcoming CTF events
CTFtime.org: upcoming CTF events
N
News and Events Feed by Topic
Recent Commits to openclaw:main
Recent Commits to openclaw:main
Scott Helme
Scott Helme
A
About on SuperTechFans
N
Netflix TechBlog - Medium
TaoSecurity Blog
TaoSecurity Blog
V
V2EX
MongoDB | Blog
MongoDB | Blog
AWS News Blog
AWS News Blog
Google DeepMind News
Google DeepMind News
Google Online Security Blog
Google Online Security Blog
O
OpenAI News
Y
Y Combinator Blog
S
Securelist
GbyAI
GbyAI
D
Docker
SecWiki News
SecWiki News
The Hacker News
The Hacker News
有赞技术团队
有赞技术团队
T
Tenable Blog
WordPress大学
WordPress大学
S
SegmentFault 最新的问题
P
Privacy International News Feed
S
Security Affairs
让小产品的独立变现更简单 - ezindie.com
让小产品的独立变现更简单 - ezindie.com
Hacker News - Newest:
Hacker News - Newest: "LLM"
H
Hackread – Cybersecurity News, Data Breaches, AI and More

串串狗小刊 ⭐️

年轻人怎么抓住 AI 发展的风口? - 串串狗小刊 为什么 GO 语言地位很尴尬? - 串串狗小刊 Web 出海必备的外链列表 - 串串狗小刊 - 聊AI、互联网、前端技术 ~ 我的 Web 3D 世界梦 - 串串狗小刊 OPC Web 出海之图视频的 AI 供应商渠道和简单外链 - 串串狗小刊 简单聊聊我的 Nodejs 世界观 - 串串狗小刊 Web 出海快速判断关键词法和推荐 3 个 SKILL - 串串狗小刊 Web 出海之演示建站盈利和朋友 Reyn 的教训 阅读源代码前要运行的 5 条 Git 命令 - 串串狗小刊 介绍几组我一直在使用的 Codex 插件 我观看哥飞年终会议复盘的 Web 出海笔记(下) - 串串狗小刊 观看哥飞年终会议复盘的 8 个 Web 出海笔记 - 串串狗小刊 Codex 敞开用的技巧和谷歌趋势的参考词 - 串串狗小刊 - 聊AI、互联网、前端技术 ~ Web 出海之外链提交频率和如何不花 Token 处理代码 - 串串狗小刊 程序员现在的最佳副业 ~ Web 出海 - 串串狗小刊 如何设计良好的 API - 串串狗小刊 - 聊AI、互联网、前端技术 ~ 你跟 AI 对话后会发生什么? - 串串狗小刊 出海 Web 之 GSC 里的曝光量和点击量和外链的关系 - 串串狗小刊 出海 Web 不要 恋战 新词游戏站 - 串串狗小刊 无港卡开通 Stripe 收款和 Nofollow 转 Dofollow 技巧 - 串串狗小刊 DeepSeek 发布氮气加速器 DSpark!可惜好东西又开源了 - 串串狗小刊 简单聊聊出海 Web 的游戏站 - 串串狗小刊 停止使用 JWT ! - 串串狗小刊 出海 SEO 之 Vercel App 找词法与 agentic-inbox 管理邮箱 - 串串狗小刊 出海 Web 之 Vercel 的必踩坑和 140 分钟需求调研 - 串串狗小刊 出海 Web 之根据调研结果,挑选需求 - 串串狗小刊 AI 时代前端写 UI 必备的 49 种 UI 风格! - 串串狗小刊 超惊艳的 3D 开放世界浏览器游戏 LAAS ,全程 Claude Fable 5 无干预开发 - 串串狗小刊 月入 4w 刀的小耳朵 sir 的出海经验 - 串串狗小刊 出海建站之 Product Hunt 的封号限制解封 - 串串狗小刊 出海 SEO 新手们,给你们分享个新词发现工具! - 串串狗小刊 Node-js 新手需要知道什么? - 串串狗小刊 - 聊AI、互联网、前端技术 ~ 用 AI 挑选 skill 头疼?聊聊四大 skill 仓库 - 串串狗小刊 让老外感受到了中国 SEO 的威力,amazing! - 串串狗小刊 驾驭工程后,AI 圈又一个新概念 Loop 工程(循环工程) - 串串狗小刊 Deepseek V4 Pro 极高的缓存命中率很重要! - 串串狗小刊 SEO 出海之田七使用 google trends 的经验 - 串串狗小刊 今年最燃Web出海奇迹,小白从0建站一个月入万刀全程详细复盘! - 串串狗小刊 - 聊AI、互联网、前端技术 ~ 两个朋友做跨境独立站编程出海的经历、找词技巧 - 串串狗小刊 - 聊AI、互联网、前端技术 ~ SEO 之用 coolify 部署 nextjs 和 面包屑 使用误区 - 串串狗小刊 注意,JS 里的 JSON.parse() 也有安全隐患! - 串串狗小刊 拆解 aidocmaker 这个 SEO 神站,聊聊 Lovart 的交互设计 - 串串狗小刊 三个最近做 SaaS 的 JS 小技巧 - 串串狗小刊 关键词评估和 reddit、HN、product hurt 起号运营小妙招! - 串串狗小刊 WASM、Rust,前端的第二条命! - 串串狗小刊 - 聊AI、互联网、前端技术 ~ SEO 之 UGC 不做落地页和 ADS 无效流量解决方法 - 串串狗小刊 SEO 之 HARO 四两拨千斤大法 - 串串狗小刊 SEO 里的 schema 和 积沙成塔 - 串串狗小刊 AI 生成的代码太啰嗦 今日 SEO 小经验分享 - 串串狗小刊 时代在轮回,2026 年做网站又开始流行起来 - 串串狗小刊 - 聊AI、互联网、前端技术 ~ 讲一下谷歌 SEO 常用的 8 个工具 - 串串狗小刊 五个谷歌 SEO 外链建设小妙招 - 串串狗小刊 分享几个 独立站 SEO 外链 建设的小经验 - 串串狗小刊 讲几个 出海独立开发 获取流量的经验 - 串串狗小刊 一个故事,把大厂互联网架构 70+ 概念串完 - 串串狗小刊 2026 年最新的 人工智能 学习路线(为期三个月) - 串串狗小刊 为什么现在的密码喜欢使用 2FA(TOTP、passkey )? - 串串狗小刊 openAI 团队告诉你,怎么把 Codex 用到极致! - 串串狗小刊 fetch 和 axios ,两者选谁? - 串串狗小刊 五年了,Zed 终于发布 1.0 版本了,简单聊聊 - 串串狗小刊 由 27 个荒废的项目,总结的 5 个失败的真相 - 串串狗小刊 今天再聊聊 Codex 的使用 - 串串狗小刊 分享几个短小精悍实用的 js 代码 - 串串狗小刊 54 天,26.9 万次连接:互联网到底有多吵? - 串串狗小刊 AI 时代前端开发最实用的 5 种设计模式 - 串串狗小刊 说 3 个前端新手可能不知道的技巧 - 串串狗小刊 Vite 这个前端打包工具是怎么工作的呢? - 串串狗小刊 - 聊AI、互联网、前端技术 ~ Vibe coding 一词发明人说 Agentic Engineering ,守住软件质量才是未来 - 串串狗小刊 如何利用 AI 理解新项目、接手新项目? - 串串狗小刊 2025 年主流的前端技术全集合 - 串串狗小刊 - 聊AI、互联网、前端技术 ~ 德鲁・布伦尼格提出是 10 个 AI 编程时代的实践经验 - 串串狗小刊 其实 React 有点难用 - 串串狗小刊 今天简单聊聊 tailwindCSS - 串串狗小刊 - 聊AI、互联网、前端技术 ~ 今天再聊聊 AI GEO,以及改善其效果的办法 - 串串狗小刊 Claude Code 向 Codex 的习惯迁移 - 串串狗小刊 几个提高 AI 提示词撰写能力的技巧 - 串串狗小刊 前端优化:核心 SEO 网页指标优化 LCP、INP 的思路 - 串串狗小刊 一个很冷门的 JS 知识点:逗号操作符 - 串串狗小刊 在 JS 中为什么要少用 class ? - 串串狗小刊 前端和后端是怎么连接的?API、RESTful、JSON、CORS都是什么? - 串串狗小刊 - 聊AI、互联网、前端技术 ~ 八个软件工程师需要了解的定理法则 - 串串狗小刊 - 聊AI、互联网、前端技术 ~ 思想实验:如果 AI 出现在 2010 年会发生什么? - 串串狗小刊 求求你别再 .filter().map().sort() 了 - 串串狗小刊 三大反向代理 Nginx、Traefik、Caddy 的区别是什么? - 串串狗小刊 为什么我觉得 adhd 病是一种智商税 ? 为什么有些人天生就不快乐 ? - 串串狗小刊 讲 3 个我这几天刚刚遇到的 CSS 里的小技巧 - 串串狗小刊 SQL数据库中什么情况该加索引?以及常见的陷阱。 - 串串狗小刊 - 聊AI、互联网、前端技术 ~ 2026 年前端死透了吗?还能入行吗? - 串串狗小刊 - 聊AI、互联网、前端技术 ~ 你其实永远也用不到数据库! - 串串狗小刊 - 聊AI、互联网、前端技术 ~ 八个和 Claude Code 编码时的小技巧 - 串串狗小刊 10 分钟快速入手 React 概念,然后开始干活儿 - 串串狗小刊
一文讲清 16 个 React 常用钩子的机制和使用场景 - 串串狗小刊
独元殇 · 2026-04-24 · via 串串狗小刊 ⭐️

[toc]

今天我整理一下笔记,把我以前记录的下面几个 react 钩子的概念和使用方式、场景简单的过一下。

是我以前在 dbuke 这个在线教程网站上学习时候做的笔记。现在这个网站貌似打不开了。

一共 6 类,16 个。这应该是涵盖 react 使用里的所有的常用钩子了(没包括一些 react 19 的),涵盖 React 日常使用!本文是手打的,不是 AI 文。

/ 01 / State Management(状态管理)
useState - 定义组件状态
useReducer - 复杂状态管理
useSyncExternalStore - 订阅外部数据源

/ 02 / Effect Hooks(副作用)
useEffect - 处理副作用
useLayoutEffect - 同步执行副作用
useInsertionEffect - 注入样式专用

/ 03 / Ref Hooks(引用)
useRef - 创建可变引用
useImperativeHandle - 暴露子组件方法

/ 04 / Performance Hooks(性能优化)
useMemo - 缓存计算结果
useCallback - 缓存函数引用
Context Hooks(上下文)
useContext - 读取上下文值

/ 05 / Transition Hooks(过渡)
useTransition - 标记非紧急更新
useDeferredValue - 延迟更新状态值

/ 06 / Random Hooks(杂项)
useDebugValue - 自定义 Hook 调试
useId - 生成唯一 ID

一共 6 类,16 个。

不深入细讲,只是简单每个都说说。

State Management(状态管理)

先说我们最常用的钩子。useState 是用到最频繁的一个。

因为 React 诞生的重要目的就是管理状态,统一管理应用状态!也就是在状态发生变化时,自动重新渲染组件。

useState - 定义组件状态

const [value, setValue] = useState('');  // 设置一个状态初始值

const handleChange = (e) => {  
  setValue(e.target.value);  // 事件一激活,就改值
};

<input
  type="text"
  value={value}
  onChange={handleChange}
/>

这个值存在第一个变量 value 里,第二个变量 setValue 是一个修改状态的函数。上面这个例子,我们在 input 里面输入什么,它就马上等于什么了。

useReducer - 复杂状态管理

useReducer 是另一个状态钩子,可以管理比 useState 更复杂的状态。这个用的少,但更强大。

const reducer = (state, action) => {
  switch (action) {
    case 'increment':
      return state + 1;
    default:
      return state;
  }
};

const [count, dispatch] = useReducer(reducer, 0);

<button onClick={() => dispatch('increment')}>Increment</button>

这个 dispatch 新函数,里面有个关键字 action,可以接收我们传入给 dispatch 的参数,然后做出更灵活的变化。

尤其是游戏界面这种,界面复杂、交互复杂的,会更好用。

useSyncExternalStore - 订阅外部数据源

然后是 useSyncExternalStore,这个钩子比较冷门。它可以把非 React 的状态,接入到 React 组件中。

Effect Hooks(副作用)

useEffect - 处理副作用

副作用钩子 useEffect,指的是组件渲染中与渲染结果无关联、但会影响环境状态的一些操作。

const [count, setCount] = useState(0);

useEffect(() => {
  document.title = `你点击了 ${count} 次`;
}, [count]);

<button onClick={() => setCount(count + 1)}>
  Click me
</button>

什么意思呢?看上面这段代码,useEffect 的第二个参数里传入了 count,那么只要这个 count 变化,就会执行里面的函数。

注意,useEffect 不应该用于”点击按钮时执行”、”获取数据时执行”这种场景。

其实并不需要经常使用这个钩子。一般我们用 useEffect 是在需要让 React 与浏览器 API 同步的时候,比如用 React 控制视频(或音频)的播放、暂停:

const ref = useRef(null); // 创建"引用",抓住视频 DOM 元素 
useEffect(() => {
  if (isPlaying) {
    ref.current.play();  // 播放
  } else {
    ref.current.pause();  // 暂停
  }
}, [isPlaying]);

<video ref={ref} src={src} loop playsInline />

当我们把 isPlaying 设置成 true 时,视频就开始播放了。这种,才是 useEffect 真正合适的场景!

useLayoutEffect - 同步执行副作用

其实还有个差不多的钩子,某些场景下更好用,叫 useLayoutEffect。它是在界面渲染之前就执行的。使用例子,在渲染前就获取某元素的高度:

const ref = useRef(null);
const [tooltipHeight, setTooltipHeight] = useState(0);

useLayoutEffect(() => {
  const { height } = ref.current.getBoundingClientRect();  // 获取提示框高度
  setTooltipHeight(height);  // 设置高度
}, []);

厉害吧!用它,浏览器还没开始渲染这个提示框,我们就获取到了这个提示框的高度,然后保存在状态里。

非常好用,可以防止页面闪烁跳跃,懂吧?

useInsertionEffect - 注入样式专用

既然比 useEffect 早,对吧?其实还有更早的。

还有一个很小众的钩子 useInsertionEffect,它专门为 CSS 和 JS 的库开发。这个运行得更早,比 useLayoutEffect 还早!专门用来确保所有的 CSS 样式都能应用到正确的组件元素上。

Ref Hooks(引用)

useRef - 创建可变引用

说说 useRef 钩子吧。

它类似于 useState,也能存状态,不过它不会触发组件渲染,所以更简单了!useRef 叫引用。

引用是可变的,而状态是不可变的。因此能使用等号运算符直接修改,比如 ref.current = 'something'。下面是一个计时器使用例子:

// 一个计时器使用案例
const [timer, setTimer] = useState(0);
const intervalRef = useRef(); // useRef 用来保存 setInterval 的 ID

const startTimer = () => {
  intervalRef.current = setInterval(() => {  // 存进去了
    setTimer((prevTimer) => prevTimer + 1);
  }, 1000);
};

const stopTimer = () => {
  clearInterval(intervalRef.current);  // 停止时就能用到
};

<p>Timer: {timer} seconds</p>
<button onClick={startTimer}>开始计时</button>
<button onClick={stopTimer}>停止计时</button>

你可能会问,为什么不直接用变量呢?因为 React 组件一更新,变量就没了…… 所以使用 React 内部的值,肯定是有用的!

useImperativeHandle - 暴露子组件方法

有个略冷门的钩子:useImperativeHandle。

转发一个引用的时候会用到。比如:

function ParentComponent() {
  const inputRef = useRef();

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

  // ...

  return (
    <>
      <CustomInput ref={inputRef} />
      <button onClick={handleFocus}>激活 input</button>
    </>
  );
}

// 上面的代码肯定无法运行
// 因此我们使用 forwardRef + useImperativeHandle,把方法暴露出去
// 把子组件传递给父组件,然后就可以用了
const CustomInput = forwardRef((props, ref) => {
  const inputRef = useRef();

  useImperativeHandle(ref, () => ({
    focus: () => {
      inputRef.current.focus();
    },
  }));

  return <input ref={inputRef} />;
});

因为直接给自定义组件(如 CustomInput)传 ref,默认是拿不到 DOM 元素的。

Performance Hooks(性能优化)

useMemo - 缓存计算结果

再说说 useMemo 这个钩子。

它用一种叫”记忆化”的方法来缓存之前的结果,以此提升应用性能。它只会在依赖项发生变化时重新计算缓存的值,非常适合执行高消耗的计算,举个例子:

function SumComponent({ numbers }) {
  const sum = useMemo(() => {  // 把求和的结果缓存起来
    return numbers.reduce((total, n) => total + n, 0);
  }, [numbers]);

  return <h1>合计: {sum}</h1>;
}

把求和的结果存起来,组件再渲染时就不会重复计算了。(只有 numbers 变化时,才会重新缓存)

useCallback - 缓存函数引用

和 useMemo 差不多,有个叫 useCallback 的钩子。

这个能缓存函数!!

比如这个例子:

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

  // 单击后会执行
  const increment = useCallback(() => {
    setCount((c) => c + 1);
  }, []);

  return (
    <>
      <div>{count}</div>
      <Button onClick={increment} />
    </>
  );
}

// button 组件
function Button({ onClick }) {
  return <button onClick={onClick}>Click me</button>;
}

因为有个问题:每次重新渲染,里面的函数都会被重新创建。那我们只要 useCallback 一下,下次再渲染,就不用重复创建 increment 函数了。

useContext - 读取上下文值

再说说 useContext 这个钩子吧。它能读取上下文(可理解为 React 版全局变量)的值:

const ThemeContext = createContext();

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

function Form() {
  const theme = useContext(ThemeContext);
  // ...
}

createContext 创建了一个值(React 版全局变量),然后这个值通过 Provider 方法给里面填充(value 放什么,就是什么),之后我们在另一个组件里(比如 Form 里)使用 useContext 就可以访问到了。

这个常用于主题逻辑。

Transition Hooks(过渡)

useTransition - 标记非紧急更新

再说说 useTransition 钩子。

这是一个过渡钩子,我们可以用它来指定某些状态的更新。这个在处理涉及大量计算的状态更新时用处很大!因为状态更新如果被立即执行,可能会导致不良的用户体验。什么意思呢?比如这个例子:

const [filter, setFilter] = useState('');
const [inputValue, setInputValue] = useState('');
const [isPending, startTransition] = useTransition();

const filteredItems = items.filter(item => item.includes(filter));

<input
  value={inputValue}
  onChange={(event) => {
    setInputValue(event.target.value);
    startTransition(() => {
      setFilter(event.target.value);
    });
  }}
  placeholder="请填充内容...."
/>

{isPending ? (
  <p>加载中...</p>
) : (
  filteredItems.map(item => <div key={item}>{item}</div>)
)}

根据用户输入,来过滤一个列表。

但是在输入框中输入时,每次输入都重新渲染,会导致 UI 卡顿。

然后我们就用 useTransition 这个钩子里的 startTransition 包裹一下,这段逻辑就被标记为”非紧急”了。

另一个值 isPending 是一个布尔值,告诉你当前是否还有状态在等待中,这样我们就可以在状态更新完成之前,给用户显示一个”加载中……”。

useDeferredValue - 延迟更新状态值

再说说 useDeferredValue 这个钩子。

它和 useTransition 很相似,不过它可以在最合适的时机更新状态。

const [query, setQuery] = useState('')
const deferredQuery = useDeferredValue(query)

一个完整的例子如下:

function FilteredList({ items }) {
  const [inputValue, setInputValue] = useState('');
  const deferredFilter = useDeferredValue(inputValue);

  const filteredItems = items.filter(item =>
    item.toLowerCase().includes(deferredFilter.toLowerCase())
  );

  return (
    <>
      <input
        value={inputValue}
        onChange={(event) => setInputValue(event.target.value)}
        placeholder="Type to filter..."
      />
      {filteredItems.map(item => <div key={item}>{item}</div>)}
    </>
  );
}

useDeferredValue 很适合像过滤列表这样的场景。无需你手动设置过渡,也不需要任何异步状态。

Random Hooks(杂项)

useId - 生成唯一 ID

说一下 useId 钩子,这是一个随机钩子。

调用它时,会创建一个唯一的 ID。

它一般用于在表单输入框之间共享的 id。什么意思呢?看看这个例子:

function EmailInput({ name }) {
  const id = useId();

  return (
    <>
      <label htmlFor={id}>{name}</label>
      <input id={id} type="email" />
    </>
  );
}

function Form() {
  return (
    <form>
      <EmailInput name="Email" />
      <EmailInput name="Confirm Email" />
    </form>
  );
}

看下面的 Form 里,两次用了 EmailInput 组件,为了防止里面的 input 冲突,于是我们就用 useId 钩子。