Composable Architecture中如何在Action内取消定时器并触发指定Action?
TCA问题:点击Fact按钮时停止定时器并触发指定Action的正确实现
问题描述
学习Composable Architecture(TCA)时,需要实现点击fact按钮时:
- 停止正在运行的定时器
- 触发
toggleTimerButtonTappedAction
尝试给.factButtonTappedAction添加.cancellable(id: CancelID.timer)未生效,寻求正确实现方式。
注意:你的代码中存在拼写错误.factButtonTapepd,正确应为.factButtonTapped,这也可能导致点击事件无法正确触发,请先修正。
错误原因分析
你当前代码中使用.cancellable(id: CancelID.timer)是给当前发起的fact请求Effect标记可取消,而非取消已在运行的定时器Effect。取消已有Effect需要使用.cancel(id:)操作,同时若要触发toggleTimerButtonTapped Action,需要在Effect中主动发送该Action或同步处理对应状态逻辑。
正确实现代码
方案一:显式触发toggleTimerButtonTapped Action
该方案复用toggleTimerButtonTapped分支的状态处理逻辑,避免重复代码:
case .factButtonTapped: state.isLoading = true return .merge( // 取消运行中的定时器Effect .cancel(id: CancelID.timer), // 触发toggleTimerButtonTapped Action,由其统一处理状态切换 .send(.toggleTimerButtonTapped), // 发起fact请求 .run { [count = state.count] send in let fact = await fetchFact(forCount: count) await send(.factResponse(fact ?? "nil")) } )
方案二:直接修改状态并取消定时器
若无需复用toggleTimerButtonTapped逻辑,可直接修改状态+取消定时器:
case .factButtonTapped: state.isLoading = true state.isTimerRunning = false return .merge( // 取消运行中的定时器Effect .cancel(id: CancelID.timer), // 发起fact请求 .run { [count = state.count] send in let fact = await fetchFact(forCount: count) await send(.factResponse(fact ?? "nil")) } )
核心说明
- 使用
.merge可以将多个Effect组合为一个返回值,同时执行取消定时器、发送Action、发起请求操作 .cancel(id: CancelID.timer)会直接终止所有标记为该ID的运行中Effect(即你的定时器循环Effect)- 两种方案可根据代码复用需求选择,最终都能实现“停止定时器+触发fact请求”的目标
内容的提问来源于stack exchange,提问作者Mc.Lover
相关产品推荐
相关产品推荐

