Anyone has an idea what could cause this error: ``...
# javascript
d
Anyone has an idea what could cause this error:
Copy code
kotlin-react-tutorial.js?92c2:40758 Uncaught TypeError: Cannot read property 'toString' of undefined
    at _no_name_provided__132.invoke_223 (kotlin-react-tutorial.js?92c2:40758)
    at _no_name_provided__83.eval [as _$render] (kotlin-react-tutorial.js?92c2:40780)
    at _no_name_provided__83.invoke_132 (kotlin-react-tutorial.js?92c2:24110)
    at eval (kotlin-react-tutorial.js?92c2:24149)
    at buildElements (kotlin-react-tutorial.js?92c2:23965)
    at _no_name_provided__84.invoke_134 (kotlin-react-tutorial.js?92c2:24124)
    at VideoList (kotlin-react-tutorial.js?92c2:24136)
    at renderWithHooks (react-dom.development.js?b313:14985)
    at updateFunctionComponent (react-dom.development.js?b313:17356)
    at beginWork (react-dom.development.js?b313:19063)
In here:
Copy code
_no_name_provided__132.prototype.invoke_223 = function ($this$rFunction, props) {
    var tmp0_iterator = props.videos.iterator_68();
    while (tmp0_iterator.hasNext_49()) {
      var video = tmp0_iterator.next_56();
      var tmp0_p_0 = null;
      var tmp1_tag_0_1 = _no_name_provided_$factory_98(tmp0_p_0);
      var tmp0_apply_0_3 = new RDOMBuilder(tmp1_tag_0_1);
>>>      tmp0_apply_0_3._set_key_(video._id.toString()); <<<<<<
      var tmp0__anonymous__1_5 = tmp0_apply_0_3._attrs_0;
      _set_onClickFunction_(tmp0__anonymous__1_5, _no_name_provided_$factory_99(props, video));
      if (video.equals(props.selectedVideo)) {
        tmp0_apply_0_3.unaryPlus_8('\u25B6 ');
      }tmp0_apply_0_3.unaryPlus_8('' + video._speaker + ': ' + video._title);
      $this$rFunction.child_4(tmp0_apply_0_3.create_11());
      Unit_getInstance();
    }
  };
I'm using the IR compiler in dev mode
m
How do that function and
class Video
look like in Kotlin?
d
The id is an Int
m
I mean please share some code. Otherwise it’s difficult to help 🙂
a
I remember having the same error. Mine was caused by
unsafeCast
So in your case, if you unsafely cast the id to an
int
that might by the problem\
d
Copy code
data class Video(val id: Int, val title: String, val speaker: String, val videoUrl: String)
Copy code
val videoList = rFunction<VideoListProps>("VideoList") { props ->
   for (video in props.videos) {
      p {
         key = video.id.toString()
it fails at the key = assignment
m
How do you set the props?
d
Copy code
videoList {
   attrs.videos = unwatchedVideos
   attrs.selectedVideo = currentVideo
   attrs.onSelectVideo = { video ->
      setCurrentVideo(video)
   }
}
a
how do you get
unwatchedVideos
d
Copy code
val app = rFunction<RProps>("App") {
   val (currentVideo, setCurrentVideo) = useState<Video?>(null)
   val (unwatchedVideos, setUnwatchedVideos) = useState<List<Video>>(listOf())
   val (watchedVideos, setWatchedVideos) = useState<List<Video>>(listOf())

   useEffect(listOf()) {
      val mainScope = MainScope()
      mainScope.launch {
         val videos = fetchVideos()
         setUnwatchedVideos(videos)
      }
   }
Copy code
suspend fun fetchVideo(id: Int): Video =
   window.fetch("<https://my-json-server.typicode.com/kotlin-hands-on/kotlinconf-json/videos/$id>")
      .await()
      .json()
      .await()
      .unsafeCast<Video>()


suspend fun fetchVideos(): List<Video> = coroutineScope {
   (1..25).map { id ->
      async {
         fetchVideo(id)
      }
   }.awaitAll()
}
It's from the kotlin js tutorial...
m
There’s your
unsafeCast
. hmm]
😂 1
d
I just upgraded deps and switched to IR and the fun started 😄
Before it seemed to work...
m
The tutorial doesn’t work with IR then. It relied on some compiler internals.\
The property used to be named
id
in JS but now it’s
_id
in IR.
You should use
kotlinx-serialization
to parse JSON from a server instead of
unsafeCast
which is the curlpit here.
Alternatively you can convert your
data class Video
to
external interface Video
. That should work as well.
d
The property used to be named 
id
 in JS but now it’s 
_id
 in IR.
why?
So I'd suppose that _id turns out to be null and doesn't have a toString()...
The Video object is internal in the kotlin code... so
external interface Video
would require me to write it in js?
m
why?
It’s an implementation detail how Kotlin properties are implemented in JS. So naming has changed from Legacy compiler to IR.
The Video object is internal in the kotlin code... so external interface Video would require me to write it in js? (edited)
No, you don’t need to implement it.
m
For
Copy code
external interface Foo { val bar: Int }
the following is sufficient in JS:
Copy code
val foo = { bar: 1 }
A simple object. And that’s returned as JSON by your API call.
You can use 
@JsExport
There’s no need here. There’s nothing to export.
r
True
m
@Sebastian Aigner the tutorial needs an update here, esp. for the IR compiler. That
unsafeCast()
for parsed JSON to
data class
is really dangerous 😉 https://play.kotlinlang.org/hands-on/Building%20Web%20Applications%20with%20React%20and%20Kotlin%20JS/08_Using_an_External_REST_API
s
Absolutely right. That was a compromise that was made to work around some other stuff at the time. That’ll be updated.
👍 3
d
Thanks for the explanation guys 👍🏼...
At the same time, you'll need to update the react-player definitions @Sebastian Aigner... I'm having problems with that too...
s
Sorry to hear that Dave. I’ll check it and address that in an update as well.
d
So far, I have:
Copy code
@file:JsModule("react-player")
@file:JsNonModule

import react.*

external object ReactPlayer {
	val default: RClass<ReactPlayerProps>
}

external interface ReactPlayerProps : RProps {
	var url: String?
		get() = definedExternally
		set(value) = definedExternally
}
and I'm getting:
Copy code
Uncaught TypeError: Cannot read property 'default' of undefined
    at VideoPlayer.render_0 (kotlin-react-tutorial.js?92c2:40913)
    at _no_name_provided__82.invoke_132 (kotlin-react-tutorial.js?92c2:24052)
    at eval (kotlin-react-tutorial.js?92c2:24142)
    at buildElements (kotlin-react-tutorial.js?92c2:23965)
    at VideoPlayer.RComponent.render_1 (kotlin-react-tutorial.js?92c2:24073)
    at VideoPlayer.RComponent.render (kotlin-react-tutorial.js?92c2:24076)
    at finishClassComponent (react-dom.development.js?b313:17485)
    at updateClassComponent (react-dom.development.js?b313:17435)
    at beginWork (react-dom.development.js?b313:19073)
    at HTMLUnknownElement.callCallback (react-dom.development.js?b313:3945)
Since
@JsName("default")
was being used...
It was supposed to be this 🤔:
Copy code
import react.*

@JsModule("react-player")
@JsNonModule
external object ReactPlayer {
	val default: RClass<ReactPlayerProps>
}

external interface ReactPlayerProps : RProps {
	var url: String?
		get() = definedExternally
		set(value) = definedExternally
}