scalajs 反应路由器。如何在条件路由中执行 ajax 请求
scalajs-react router. How to perform ajax request inside conditional route
我正在尝试制作一些有条件的路线。条件在服务器端解决。
路由规则示例:
| (dynamicRouteCT("#user" / long.caseClass[User]) ~> dynRender((page: User) => <.div("Hello, " + page.id.toString)))
.addCondition((page: User) => checkPermissions(page.id))(_ => Some(redirectToPage(Page403)(Redirect.Push)))
checkpermissions
正文:
def checkPermissions(id: Long) = CallbackTo.future{
/*Ajax.get(s"http://some.uri/?id=$id") map (res =>
* if (something) true
* else false
* )
*/
//the request before returns Future[XMLHttprequest] witch maps to Future[Boolean]
Future(false)
}
我的类型不匹配:(page: User) => checkPermissions(page.id)
是否可以在条件路由中执行 ajax 请求?
如果我们查看 def addCondition(cond: Page => CallbackTo[Boolean])(condUnmet: Page => Option[Action[Page]]): Rule[Page]
,我们会发现它需要一个 CallbackTo[Boolean]
。由于 JS 环境的性质,现在有从 Future[A]
到 A
的方法。虽然这不是 scalajs-react 本身的限制,但它是一个继承的现实,会影响你的 scalajs-react 代码;正如 this table in the doc 所示,无法从 CallbackTo[Future[Boolean]]
变为 CallbackTo[Boolean]
。
这种类型级别的限制对于用户体验来说其实是一件非常好的事情。路由器是同步的,它必须立即决定如何渲染路由和路由变化。如果它被允许异步并以某种方式支持 Future
s,那么用户将在没有任何视觉反馈或中断方式的情况下体验明显的(并且可能是巨大的)延迟。
"right way"解决这个问题的方法是使用覆盖异步状态的模型。这就是我要做的:
- 创建一个
AsyncState[E, A]
ADT 案例:Empty
、AwaitingResponse
、Loaded(value: A)
、Failed(error: E)
。
(如果需要,您可以进一步丰富这些,例如 Loaded
上的 loadTime、Failed
上的重试回调、AwaitingResponse
上的 timeStarted 等)
- 在您的(local/client-side)状态下有一个
AsyncState[Boolean]
实例。
- 可选择在页面启动时启动异步加载。
- 让路由器将其值传递给组件and/or检查此值。
(路由器不知道该值,因为它是动态的,请使用Callback
在理解中将事物连接起来并满足类型。)
- 根据
AsyncState[Boolean]
的值,呈现对用户有意义的内容。如果是 AwaitingResponse
,显示一个小旋转器;如果失败则显示错误并可能显示重试按钮。
(还应注意,AsyncState[Boolean]
实际上不应该是 Boolean
,因为这对域的描述性或真实性不强。它可能更有意义,例如 AsyncState[UserAccess]
或类似的东西。)
希望对您有所帮助!祝你好运!
我正在尝试制作一些有条件的路线。条件在服务器端解决。
路由规则示例:
| (dynamicRouteCT("#user" / long.caseClass[User]) ~> dynRender((page: User) => <.div("Hello, " + page.id.toString)))
.addCondition((page: User) => checkPermissions(page.id))(_ => Some(redirectToPage(Page403)(Redirect.Push)))
checkpermissions
正文:
def checkPermissions(id: Long) = CallbackTo.future{
/*Ajax.get(s"http://some.uri/?id=$id") map (res =>
* if (something) true
* else false
* )
*/
//the request before returns Future[XMLHttprequest] witch maps to Future[Boolean]
Future(false)
}
我的类型不匹配:(page: User) => checkPermissions(page.id)
是否可以在条件路由中执行 ajax 请求?
如果我们查看 def addCondition(cond: Page => CallbackTo[Boolean])(condUnmet: Page => Option[Action[Page]]): Rule[Page]
,我们会发现它需要一个 CallbackTo[Boolean]
。由于 JS 环境的性质,现在有从 Future[A]
到 A
的方法。虽然这不是 scalajs-react 本身的限制,但它是一个继承的现实,会影响你的 scalajs-react 代码;正如 this table in the doc 所示,无法从 CallbackTo[Future[Boolean]]
变为 CallbackTo[Boolean]
。
这种类型级别的限制对于用户体验来说其实是一件非常好的事情。路由器是同步的,它必须立即决定如何渲染路由和路由变化。如果它被允许异步并以某种方式支持 Future
s,那么用户将在没有任何视觉反馈或中断方式的情况下体验明显的(并且可能是巨大的)延迟。
"right way"解决这个问题的方法是使用覆盖异步状态的模型。这就是我要做的:
- 创建一个
AsyncState[E, A]
ADT 案例:Empty
、AwaitingResponse
、Loaded(value: A)
、Failed(error: E)
。
(如果需要,您可以进一步丰富这些,例如Loaded
上的 loadTime、Failed
上的重试回调、AwaitingResponse
上的 timeStarted 等) - 在您的(local/client-side)状态下有一个
AsyncState[Boolean]
实例。 - 可选择在页面启动时启动异步加载。
- 让路由器将其值传递给组件and/or检查此值。
(路由器不知道该值,因为它是动态的,请使用Callback
在理解中将事物连接起来并满足类型。) - 根据
AsyncState[Boolean]
的值,呈现对用户有意义的内容。如果是AwaitingResponse
,显示一个小旋转器;如果失败则显示错误并可能显示重试按钮。
(还应注意,AsyncState[Boolean]
实际上不应该是 Boolean
,因为这对域的描述性或真实性不强。它可能更有意义,例如 AsyncState[UserAccess]
或类似的东西。)
希望对您有所帮助!祝你好运!