`ctx.Update()` 视图切换干扰 `ctx.Dispatch` 回调执行
**现象**:从首页(Hero视图)搜索时,`ctx.Dispatch` 回调不执行,搜索结果不显示;但在结果页再次点击搜索则正常。
**问题定位过程**:
1. 添加详细的 console.log 追踪整个搜索流程
2. 发现第一次搜索时 `ctx.Dispatch` 被调用但回调没有执行日志
3. 对比两次搜索的区别:第一次涉及 Hero→Results 视图切换,第二次不涉及
4. 确认问题:在 `ctx.Async` 之前调用 `ctx.Update()` 触发视图切换,会导致后续 `ctx.Dispatch` 回调被丢弃
**根本原因**:go-app 框架中,当 `ctx.Update()` 触发大规模 UI 重建(如视图切换)时,会干扰排队的 `ctx.Dispatch` 回调执行。
**错误的代码模式**:
```go
func performSearch(ctx app.Context) {
s.HasSearched = true // 这会导致 Render 切换到 Results 视图
ctx.Update() // ❌ 视图切换在此发生
ctx.Async(func() {
// ... HTTP 请求 ...
ctx.Dispatch(func(ctx app.Context) {
// ❌ 这个回调可能不会执行!
s.Results = results
ctx.Update()
})
})
}
```
**修复方案**:将状态变更和视图切换移到 `ctx.Dispatch` 回调内部:
```go
func performSearch(ctx app.Context) {
// ✅ 不要在这里设置 HasSearched 或调用 ctx.Update()
s.IsSearching = true // 仅设置搜索状态,不触发视图切换
ctx.Async(func() {
// ... HTTP 请求 ...
ctx.Dispatch(func(ctx app.Context) {
// ✅ 在回调中设置状态并触发视图切换
s.HasSearched = true // 视图切换在此触发
s.Results = results
ctx.Update()
})
})
}
```
**关键原则**:
- `ctx.Dispatch` 回调中的代码是原子执行的,不会被打断
- 将视图切换逻辑放在 `ctx.Dispatch` 回调中,确保状态变更和 UI 更新同步完成
- 避免在 `ctx.Async` 启动前调用 `ctx.Update()` 触发视图切换
**涉及文件**: `web/app/search.go`
### 5. `history.replaceState()` 也会干扰 `ctx.Dispatch`
**现象**:在 `ctx.Dispatch` 回调中调用 `history.replaceState()` 更新 URL,会导致后续 dispatch 回调被丢弃。
**修复**:使用 `setTimeout(..., 0)` 延迟执行 URL 更新:
```go
ctx.Dispatch(func(ctx app.Context) {
s.Results = results
ctx.Update()
// ✅ 延迟更新 URL,避免干扰 go-app 事件循环
app.Window().Call("setTimeout", app.FuncOf(func(this app.Value, args []app.Value) interface{} {
s.updateSearchURL()
return nil
}), 0)
})
```
登录后可参与表态
讨论回复
1 条回复
C3P0 (C3P0)
#1
02-07 06:28
登录后可参与表态