refactor(voice-materials): phase 3 extract hooks #866

Merged
xiaoxia merged 2 commits from refactor/voice-material-library-phase3 into develop 2026-07-25 10:04:02 +08:00
Owner

Phase 3 — 抽离业务逻辑 Hook

从 VoiceMaterialLibrary.tsx 中按领域抽离 4 个自定义 Hook,主文件从 ~1100 行降到 ~600 行,专注 UI 渲染组装。

抽离的 Hook

Hook 职责 行数
useVoiceMaterials 素材列表查询、筛选状态、增删改操作 ~350行
useAudioPlayer 音频播放控制(播放/暂停/进度/音量) ~140行
useBatchOperations 批量选择、批量删除、批量打标签 ~130行
useTtsSynthesize TTS 合成状态管理、轮询、保存到素材库 ~135行

变更说明

  • 功能不变,纯结构重构
  • 主组件 VoiceMaterialLibrary 变为组装器,只负责渲染
  • 每个 Hook 职责单一,便于后续维护和单测
  • 新增 useAudioPlayer 单元测试

相关 PR

  • Phase 1: #846 已合入
  • Phase 2: #858 待合入
## Phase 3 — 抽离业务逻辑 Hook 从 VoiceMaterialLibrary.tsx 中按领域抽离 4 个自定义 Hook,主文件从 ~1100 行降到 ~600 行,专注 UI 渲染组装。 ### 抽离的 Hook | Hook | 职责 | 行数 | |------|------|------| | `useVoiceMaterials` | 素材列表查询、筛选状态、增删改操作 | ~350行 | | `useAudioPlayer` | 音频播放控制(播放/暂停/进度/音量) | ~140行 | | `useBatchOperations` | 批量选择、批量删除、批量打标签 | ~130行 | | `useTtsSynthesize` | TTS 合成状态管理、轮询、保存到素材库 | ~135行 | ### 变更说明 - 功能不变,纯结构重构 - 主组件 VoiceMaterialLibrary 变为组装器,只负责渲染 - 每个 Hook 职责单一,便于后续维护和单测 - 新增 useAudioPlayer 单元测试 ### 相关 PR - Phase 1: #846 ✅ 已合入 - Phase 2: #858 待合入
auto-approve-bot approved these changes 2026-07-25 03:50:02 +08:00
auto-approve-bot left a comment
Collaborator

CI全绿,自动审批通过。

CI全绿,自动审批通过。
auto-approve-bot approved these changes 2026-07-25 03:50:02 +08:00
auto-approve-bot left a comment
Collaborator

CI全绿,自动审批通过。

CI全绿,自动审批通过。
xiaoxia added 2 commits 2026-07-25 09:06:03 +08:00
从 VoiceMaterialLibrary.tsx 中抽离以下自定义 Hook:

- useVoiceMaterials: 素材列表查询、筛选状态、增删改操作
- useAudioPlayer: 音频播放控制(播放/暂停/进度/音量)
- useBatchOperations: 批量选择、批量删除、批量打标签
- useTtsSynthesize: TTS 合成状态管理、轮询、保存到素材库

主文件从 1108 行减少到 603 行,专注 UI 渲染组装。

新增 useAudioPlayer 单元测试。
fix: 修复 useBatchOperations 中 tagAsset 导入路径错误(应从@/api/tags导入)
CI/CD Pipeline / Check if frontend-only change (pull_request) Successful in 21s
CI/CD Pipeline / Validate - Migration (alembic) (pull_request) Successful in 58s
CI/CD Pipeline / Frontend Lint (pull_request) Successful in 38s
CI/CD Pipeline / Validate - Type Check (mypy) (pull_request) Successful in 59s
CI/CD Pipeline / PR Build Worker Image (pull_request) Successful in 26s
CI/CD Pipeline / Build Staging API Image (pull_request) Has been skipped
CI/CD Pipeline / Build Staging Web Image (pull_request) Has been skipped
CI/CD Pipeline / Build Staging Worker Image (pull_request) Has been skipped
CI/CD Pipeline / Validate - Code Quality (pull_request) Successful in 2m46s
PR Automation / Auto Approve on CI Green (pull_request) Successful in 1m15s
CI/CD Pipeline / Unit Tests (pull_request) Has been skipped
CI/CD Pipeline / PR Build Web Image (pull_request) Successful in 2m5s
CI/CD Pipeline / Build Production API Image (pull_request) Has been skipped
CI/CD Pipeline / Build Production Web Image (pull_request) Has been skipped
CI/CD Pipeline / Build Production Worker Image (pull_request) Has been skipped
CI/CD Pipeline / Deploy Staging (Watchtower auto-deploy) (pull_request) Has been skipped
CI/CD Pipeline / Integration Tests (pull_request) Has been skipped
CI/CD Pipeline / Deploy Production (pull_request) Has been skipped
Preview Deploy / Deploy Preview Environment (pull_request) Failing after 29s
CI/CD Pipeline / Staging E2E Tests (pull_request) Has been skipped
CI/CD Pipeline / Staging API Integration Tests (pull_request) Has been skipped
CI/CD Pipeline / ACR Image Cleanup (pull_request) Has been skipped
CI/CD Pipeline / Production Browser E2E (pull_request) Has been skipped
CI/CD Pipeline / Frontend Unit Tests (pull_request) Successful in 39s
CI/CD Pipeline / PR Build API Image (pull_request) Successful in 4m24s
AI Code Review / AI Code Review (pull_request) Successful in 5m48s
PR Automation / Auto Merge on CI Green + Approved (pull_request) Successful in 47m38s
Preview Cleanup / Cleanup Preview Environment (pull_request) Successful in 9s
74243f009e
xiaoxia force-pushed refactor/voice-material-library-phase3 from 77c82285f1 to 74243f009e 2026-07-25 09:06:03 +08:00 Compare
Collaborator

代码审查结果 - PR #866

⚠️ 问题(2个需要修改)

  1. apps/web/src/pages/voice-materials/hooks/useAudioPlayer.ts 第99行:使用 setTimeout 硬编码 100ms 延迟来设置音频进度,存在竞态条件和不可靠性。

    • 原因:在 handleSeek 中,如果音频未初始化,会调用 startPlayback 并通过 setTimeout 等待 100ms 后设置 currentTime。如果音频加载较慢或浏览器繁忙,100ms 后 audioRef.current 可能尚未准备好,导致跳转失败或从 0 开始播放。
    • 后果:用户点击进度条跳转时,音频可能会从头开始播放而不是跳转到指定位置,体验极差。
    • 建议:在 startPlayback 中创建 Audio 对象后立即设置 currentTime,或者在 canplay 事件回调中设置进度,避免使用不可靠的延时。
  2. apps/web/src/pages/voice-materials/hooks/useAudioPlayer.ts 第32-131行:事件监听器未清理,存在内存泄漏风险。

    • 原因:在 startPlayback 中为 audio 对象添加了 timeupdateended 事件监听器,但在 stopPlayback 和组件卸载的 useEffect 清理函数中,仅调用了 pause() 和将引用置空,未调用 removeEventListener
    • 后果:虽然引用置空有助于 GC,但在高频操作或组件频繁挂载/卸载的场景下,未移除的监听器可能导致旧的 Audio 对象无法被及时回收,造成内存泄漏。
    • 建议:在 stopPlayback 和 cleanup 函数中,显式移除 timeupdateended 事件监听器。

💡 建议(1个可选)

  1. apps/web/src/pages/voice-materials/hooks/useAudioPlayer.ts 第43行timeupdate 事件触发频率极高,直接更新 React State 可能导致父组件不必要的频繁重渲染。
    • 说明timeupdate 通常每秒触发多次,每次调用 setCurrentTime 都会触发 Hook 消费者(父组件)重渲染。如果父组件渲染树较重,会造成性能卡顿。
    • 建议:考虑使用 requestAnimationFrame 节流更新 UI,或者将 currentTime 存储在 Ref 中,仅通过单独的同步机制或节流回调更新 State。

格式检查通过 | 逻辑审查需修改 | ⚠️ 建议关注性能


🤖 由 AI 代码审查机器人自动生成 | 2026-07-25 01:13:22 | 模型:

## 代码审查结果 - PR #866 ### ⚠️ 问题(2个需要修改) 1. **apps/web/src/pages/voice-materials/hooks/useAudioPlayer.ts 第99行**:使用 `setTimeout` 硬编码 100ms 延迟来设置音频进度,存在竞态条件和不可靠性。 - **原因**:在 `handleSeek` 中,如果音频未初始化,会调用 `startPlayback` 并通过 `setTimeout` 等待 100ms 后设置 `currentTime`。如果音频加载较慢或浏览器繁忙,100ms 后 `audioRef.current` 可能尚未准备好,导致跳转失败或从 0 开始播放。 - **后果**:用户点击进度条跳转时,音频可能会从头开始播放而不是跳转到指定位置,体验极差。 - **建议**:在 `startPlayback` 中创建 `Audio` 对象后立即设置 `currentTime`,或者在 `canplay` 事件回调中设置进度,避免使用不可靠的延时。 2. **apps/web/src/pages/voice-materials/hooks/useAudioPlayer.ts 第32-131行**:事件监听器未清理,存在内存泄漏风险。 - **原因**:在 `startPlayback` 中为 `audio` 对象添加了 `timeupdate` 和 `ended` 事件监听器,但在 `stopPlayback` 和组件卸载的 `useEffect` 清理函数中,仅调用了 `pause()` 和将引用置空,未调用 `removeEventListener`。 - **后果**:虽然引用置空有助于 GC,但在高频操作或组件频繁挂载/卸载的场景下,未移除的监听器可能导致旧的 `Audio` 对象无法被及时回收,造成内存泄漏。 - **建议**:在 `stopPlayback` 和 cleanup 函数中,显式移除 `timeupdate` 和 `ended` 事件监听器。 ### 💡 建议(1个可选) 1. **apps/web/src/pages/voice-materials/hooks/useAudioPlayer.ts 第43行**:`timeupdate` 事件触发频率极高,直接更新 React State 可能导致父组件不必要的频繁重渲染。 - **说明**:`timeupdate` 通常每秒触发多次,每次调用 `setCurrentTime` 都会触发 Hook 消费者(父组件)重渲染。如果父组件渲染树较重,会造成性能卡顿。 - **建议**:考虑使用 `requestAnimationFrame` 节流更新 UI,或者将 `currentTime` 存储在 Ref 中,仅通过单独的同步机制或节流回调更新 State。 --- ✅ 格式检查通过 | ❌ 逻辑审查需修改 | ⚠️ 建议关注性能 --- <sub>🤖 由 AI 代码审查机器人自动生成 | 2026-07-25 01:13:22 | 模型: </sub> <!-- AI_CODE_REVIEW_AUTO_COMMENT -->
xiaoxia merged commit ee2cc0e7a1 into develop 2026-07-25 10:04:02 +08:00
xiaoxia deleted branch refactor/voice-material-library-phase3 2026-07-25 10:04:02 +08:00

🗑️ 预览环境已清理

PR #866 已关闭或合并,对应的预览环境已被清理。

如有需要,可以重新打开 PR 来重新生成预览环境。

🗑️ **预览环境已清理** PR #866 已关闭或合并,对应的预览环境已被清理。 > 如有需要,可以重新打开 PR 来重新生成预览环境。
Sign in to join this conversation.