Slinky/Scala.js环境中调用异步函数导致渲染失败
Scala.js + Slinky Native 异步调用报错问题解决
问题背景
不确定该问题属于Scala.js通用问题,还是Slinky/Slinky-native/Slinky-hot的特定问题。使用的依赖如下:
libraryDependencies += "me.shadaj" %%% "slinky-native" % "0.7.0" libraryDependencies += "me.shadaj" %%% "slinky-hot" % "0.7.0" addSbtPlugin("org.scala-js" % "sbt-scalajs" % "1.10.1")
代码实现
编写了用于获取Facebook登录状态的异步函数:
object LoginController { def userFBLoginStatus: Future[LoginStatus] = { FBAccessToken.getCurrentAccessToken.toFuture.map {
其中调用的JavaScript库静态函数定义如下:
@native @JSImport("react-native-fbsdk-next", JSImport.Default) object FBAccessToken extends js.Object { def getCurrentAccessToken: Promise[FBAccessToken | Null] = native }
在主App组件中调用该异步函数:
@react class App extends Component { type Props = Unit type State = Boolean def initialState = false override def componentDidMount(): Unit = { LoginController.userFBLoginStatus.map { case LoggedIn => setState(true) case LoggedOut => setState(false) } } override def render(): ReactElement = { if (state) View(//welcome view) else View(//login page view)
报错情况
预期通过componentDidMount中的异步函数返回结果切换视图,sbt clean fastOptJS执行无异常,但应用渲染时出现以下报错:
TypeError: undefined is not an object (evaluating 'this$.then') This error is located at: in App$ (at renderApplication.js:50) in RCTView (at View.js:32) in View (at AppContainer.js:92) in RCTView (at View.js:32) in View (at AppContainer.js:119) in AppContainer (at renderApplication.js:43) in DanceApp(RootComponent) (at renderApplication.js:60) ERROR TypeError: undefined is not an object (evaluating 'this$.then')
注释掉componentDidMount中的异步调用后,渲染恢复正常。从报错信息(evaluating 'this$.then')推断,问题出在Promise的then方法调用上,可能是获取到的对象并非预期的Promise实例。
等价的React JavaScript代码可以正常运行:
class Map extends Component { constructor () { super() this.state = { wells: [] } } componentDidMount() { this.props.fetchWells() .then(res => this.setState({ wells: res.wells }) ) } render () { const { wells } = this.state return wells.length ? this.renderWells() : ( <span>Loading wells...</span> ) } }
解决方案
修改JSImport的导入方式,将默认导出改为指定具体的导出名称AccessToken,问题解决。修改后的代码如下:
@native @JSImport("react-native-fbsdk-next", "AccessToken") object FBAccessToken extends js.Object { def getCurrentAccessToken(): Promise[FBAccessToken | Null] = native }
内容的提问来源于stack exchange,提问作者arinray
相关产品推荐
相关产品推荐

