Hook:从前端到 CLI,同一个思想
Hook 是一个贯穿软件设计的通用概念:在特定时机自动执行的回调函数,让你能”挂入”框架的生命周期或数据流,而不需要修改框架本身。核心思想是控制反转(IoC)——不是你调用框架,而是框架在恰当的时候回调你。
本文从三个层面梳理 Hook 的应用:前端开发中的 Hook、Claude Code 的 Hook 机制、以及如何实际配置 Hook。
前端中的 Hook
在前端领域,Hook 以多种形态出现,但本质相同:框架定义了”何时”,你定义”做什么”。
React Hooks
最常见的 Hook 含义。useState、useEffect、useCallback 等让函数组件拥有状态管理、副作用处理等能力。本质是 React 在渲染和提交阶段调用你的函数。
生命周期钩子
Vue 的 onMounted、onUnmounted,或 React class 组件的 componentDidMount——框架在组件的特定阶段调用你注册的函数。
构建工具钩子
Webpack 的 tapable、Vite 的 Rollup-plugin-hooks——在打包过程的特定阶段(如编译前、生成后)注入自定义逻辑。
Git Hooks
pre-commit、pre-push——在 git 操作的特定时机触发自定义脚本。
Claude Code 的 Hook 机制
Claude Code 提供了一套 Hook 系统,本质和前端 Hook 是同一个思路——在固定时机自动调用你定义的逻辑,只是这里挂入的是 Claude Code 的工具调用生命周期。
PreToolUse Hook
在工具调用之前执行。通过退出码控制行为:
| 退出码 | 行为 |
|---|---|
0 | 允许——继续执行工具 |
2 | 拒绝——阻止工具调用,stderr 内容会反馈给 Claude |
| 其他 | 阻断并返回输出 |
PostToolUse Hook
在工具调用完成之后执行。拿到工具的输出结果,可以做后续处理(如自动格式化、运行测试)。
其他 Hook 类型
- Notification——Claude 发通知时触发(比如任务完成)
- Stop——Claude 停止响应时触发
环境变量
Hook 命令中可以访问以下环境变量:
$CLAUDE_TOOL_NAME——当前工具名$CLAUDE_FILE_PATH——操作的文件路径$CLAUDE_SESSION_ID——会话 ID
同时 stdin 会传入工具参数的 JSON,包含 tool_name、tool_input 等字段。
实战:配置 Claude Code Hook
配置位置
| 文件 | 作用域 |
|---|---|
~/.claude/settings.json | 全局(所有项目) |
.claude/settings.json | 项目级(提交到 git) |
.claude/settings.local.json | 项目级(个人,不提交) |
基本结构
{ "hooks": { "PreToolUse": [ { "matcher": "Bash", "hooks": [{ "type": "command", "command": "你的命令" }] } ], "PostToolUse": [ { "matcher": "Write|Edit", "hooks": [{ "type": "command", "command": "你的命令" }] } ] }}关键字段
- matcher——匹配工具名:
Bash、Write、Edit、Read,用|组合如"Write|Edit"。不设 matcher 则对所有工具生效。 - command——收到 stdin JSON,包含
tool_name、tool_input - 退出码:
0= 放行,2= 拒绝,其他 = 阻断
典型用途
- 写入后自动格式化——PostToolUse +
"Write|Edit"matcher - 拦截危险命令——PreToolUse +
"Bash"matcher,检测rm -rf等 - 记录审计日志——PreToolUse,记录所有 Bash 命令
- 写完后跑测试——PostToolUse +
"Write|Edit",npm test/uv run pytest
小结
无论是 React 的 useEffect、Webpack 的插件钩子、Git 的 pre-commit,还是 Claude Code 的 PreToolUse/PostToolUse,Hook 的本质始终如一:框架提供挂载点,你注入自定义逻辑。 理解了这一点,面对任何新框架的 Hook 系统,都能快速上手。