scalajs-react中处理AJAX响应的惯用方法及Success分支不执行问题
问题原因
你当前的写法存在两个核心问题:
case Success分支中仅构造了Callback实例但没有执行,所以Callback.log对应的逻辑完全不会运行- 直接在
Callback包裹的代码块中使用原生Future#onComplete,和scalajs-react的异步管控体系割裂,后续要对接组件状态更新、副作用清理都会很麻烦
scalajs-react 惯用实现方式
scalajs-react生态中统一使用AsyncCallback处理异步操作,它可以和原生Callback、组件状态更新逻辑无缝组合,也内置了错误处理、异步取消等能力。
基础实现(仅输出响应内容)
import japgolly.scalajs.react._ import japgolly.scalajs.react.extra.Ajax import scala.util.Try def showAllEmployees: Callback = // 封装GET请求为AsyncCallback Ajax.get("http://localhost:8081/fetchAllEmployees").asAsyncCallback // 处理成功响应:输出日志 .flatMap(xhr => Callback.log(xhr.responseText)) // 处理异常 .handleError(t => Callback.println(s"An error has occurred: ${t.getMessage}")) // 触发异步执行(如果是在组件事件回调中返回该AsyncCallback,可省略此步,框架会自动执行) .runAsync
进阶实现(解析响应并存入组件状态)
如果需要将响应解析为业务实体、更新到组件状态,可以直接在AsyncCallback的组合链中添加对应逻辑:
import upickle.default._ // 定义业务实体和序列化规则,也可使用circe等其他序列化库 case class Employee(id: Long, name: String, department: String) derives ReadWriter case class State(employees: List[Employee] = Nil, loading: Boolean = false) val component = ScalaComponent.builder[Unit] .initialState(State()) .renderS { (_, state) => <.div( <.button( ^.disabled := state.loading, ^.onClick --> fetchAndUpdateEmployees, // 直接绑定AsyncCallback到点击事件,无需手动run "加载员工列表" ), <.ul( state.employees.map(emp => <.li(s"${emp.id} | ${emp.name} | ${emp.department}")) ) ) } .build // 完整的请求+解析+更新状态逻辑 def fetchAndUpdateEmployees: AsyncCallback[Unit] = for { // 更新状态为加载中 _ <- AsyncCallback.lift(Callback.modify(_.copy(loading = true))) // 发起请求 xhr <- Ajax.get("http://localhost:8081/fetchAllEmployees").asAsyncCallback // 解析响应 emps <- AsyncCallback.fromTry(Try(read[List[Employee]](xhr.responseText))) // 更新状态:写入员工列表、取消加载状态 _ <- AsyncCallback.lift(Callback.set(State(employees = emps, loading = false))) } yield () // 全局异常处理 .handleErrorWith(t => AsyncCallback.lift( Callback.modify(_.copy(loading = false)) >> Callback.println(s"请求失败:${t.getMessage}") ))
原写法快速修复(不推荐)
如果只是要让现有代码的Success分支生效,只需给构造出的Callback加执行调用即可,但这种方式不适合复杂场景:
case Success(xhr) => Callback.log(xhr.responseText).runNow()
内容的提问来源于stack exchange,提问作者Mandroid
相关产品推荐
相关产品推荐

