问题描述
在 Vue 3 组件中,通过 `props.taskId` 传递任务 ID 给子组件,子组件在 `open()` 方法中尝试使用 `props.taskId` 加载数据,但数据加载失败。即使父组件已经设置了 `props.taskId`,子组件的 `open()` 方法执行时 `props.taskId` 仍然是 `undefined` 或旧值。
具体表现:
- 父组件调用 `performanceViewerRef.value?.open()` 时传递了正确的 `taskId`
- 子组件的 `open()` 方法中 `props.taskId` 仍然是 `undefined`
- 数据加载方法因为缺少 `taskId` 而失败
- 前端日志显示 `hasTaskId: false`
根本原因
Vue 3 的响应式系统是异步的。当父组件更新 `props` 并立即调用子组件方法时,`props` 的更新可能还没有完成,导致子组件方法中访问的 `props` 仍然是旧值。
具体原因:
1. **响应式更新是异步的**:Vue 3 的响应式更新在下一个 tick 才生效
2. **方法调用时机**:父组件在设置 `props` 后立即调用子组件方法,此时 `props` 可能还未更新
3. **依赖 props 的方法**:子组件的 `open()` 方法直接依赖 `props.taskId`,而不是通过参数传递
解决方案
修改子组件方法,接受 `taskId` 作为直接参数,而不是依赖 `props`:
```typescript
// 在 StreamPerformanceViewer.vue 中
const open = async (taskIdParam?: string) => {
visible.value = true;
const effectiveTaskId = taskIdParam || props.taskId;
if (!effectiveTaskId) {
console.error('[Performance] open() called without a valid taskId.');
return;
}
await nextTick();
await loadTaskWithId(effectiveTaskId);
await loadPerformanceDataWithId(effectiveTaskId);
// ...
};
// 创建独立的方法,直接使用传入的 taskId
const loadTaskWithId = async (id: string) => {
// 使用 id 而不是 props.taskId
const result = await window.electronAPI.invoke('stream:getTask', { taskId: id });
// ...
};
const loadPerformanceDataWithId = async (id: string) => {
// 使用 id 而不是 props.taskId
const result = await window.electronAPI.invoke('stream:getPerformanceHistory', {
taskId: id,
duration: HISTORY_DURATION,
});
// ...
};
```
父组件调用时直接传递 `taskId`:
```typescript
// 在 StreamStatus.vue 中
const handleViewPerformance = (task: StreamTask) => {
selectedTaskId.value = task.id; // 仍然更新用于其他用途
performanceViewerRef.value?.open(task.id); // 直接传递 taskId
};
```
关键修改点:
1. **方法参数化**:`open()` 方法接受 `taskId` 作为参数
2. **独立的数据加载方法**:创建 `loadTaskWithId()` 和 `loadPerformanceDataWithId()`,直接使用传入的 `id`
3. **父组件直接传递**:父组件调用时直接传递 `task.id`,不依赖 `props` 更新
背景信息
这是一个基于 Electron + Vue 3 + TypeScript 的推流监控应用。性能监控组件通过 `props` 接收 `taskId`,并在对话框打开时加载对应的性能数据。
技术栈:
- **前端框架**:Vue 3 + TypeScript
- **UI 库**:Element Plus
- **图表库**:Chart.js
- **通信**:Electron IPC
组件结构:
- `StreamStatus.vue` - 父组件,显示任务列表
- `StreamPerformanceViewer.vue` - 子组件,显示性能监控图表
问题发现过程:
1. 性能监控页面打开后数据为空
2. 检查日志发现 `loadPerformanceData` 方法没有被调用
3. 进一步检查发现 `props.taskId` 在 `open()` 方法执行时为 `undefined`
4. 添加日志确认 Vue 响应式更新的异步性
5. 修改为直接传递参数的方式解决问题
相关文件:
- `src/renderer/components/StreamPerformanceViewer.vue` - 性能监控组件
- `src/renderer/components/StreamStatus.vue` - 任务状态组件