You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

scalajs-react中处理AJAX响应的惯用方法及Success分支不执行问题

问题原因

你当前的写法存在两个核心问题:

  1. case Success分支中仅构造了Callback实例但没有执行,所以Callback.log对应的逻辑完全不会运行
  2. 直接在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

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.10.02 01:45:01