Kotlin/JSのハマりポイント！【随時更新】


忘備録的な感じで残しておきます
なんかわかれば追加するかもです

https://github.com/naotiki/naotiki.github.io

↑実際にKotlin/JSで作成したポートフォリオのようなものです。

:::note warn
**本記事はkotlin-wrappers `1.0.0-pre.545`を対象として書かれています。**

kotlin-wrappersはこれからの更新でも大量の破壊的変更が伴うことが予想されるため、バージョンが少しでも違う場合はこの記事を参考にしないほうがいい可能性があります。
:::

# [React Router] BrowserRouterが使えない！？
WebpackConfigでdevServer内のhistoryApiFallbackをtrueにする必要があるのですが、`build.gradle.kts`内の`commonWebpackConfig`から変更することができないため`webpack.config.d/webpack.config.js`を作成し、
```js
if (config.devServer){
    //上書きしないようassign
    config.devServer = Object.assign(config.devServer, {
        historyApiFallback: true,
    });
}
```
このように書きます。
# [Emotion] styled('xxx')((...) => ...)←どう書くんや
MUIのAppBarのpositionをfixedにするときに困りました

https://mui.com/material-ui/react-app-bar/#fixed-placement

```javascript
const Offset = styled('div')(({ theme }) => theme.mixins.toolbar);
```
↓Kotlin/JSではこのように書きます
```kotlin
val Offset = div.styled {
     +it.asDynamic().theme.unsafeCast<mui.material.styles.Theme>().mixins.toolbar.unsafeCast<Properties>()
}
```
`+`で`Properties?.unaryPlus()`を呼び出しています。
```kotlin
sealed class PropertiesBuilder :
    Properties,
    RuleBuilder<PropertiesBuilder>,
    PseudosRuleBuilder<PropertiesBuilder> {
    //↓おまえか！？！？！？
    inline operator fun Properties?.unaryPlus() {
        Object.assign(this@PropertiesBuilder, this)
    }
}
```
キャストしないとIntelliJくんが`Properties?.unaryPlus()`出してくれないので罠ですこれ。
# [React] PropsにReactNodeを渡したい！！！！
こんな感じで`create`をつけましょう
```kotlin
CardHeader {
    title = Typography.create {
        variant = TypographyVariant.h6
        +it.name
    }
}
```
前は`createElement{}`で囲むとできた

https://qiita.com/naotikiKt/items/98842da265780bb14e9f
# Node.jsをダウンロードしたくない！/ バージョンを変えたい！
build.gradle.ktsに追記しましょう
```kotlin:build.gradle.kts
rootProject.plugins.withType<org.jetbrains.kotlin.gradle.targets.js.nodejs.NodeJsRootPlugin> {
    rootProject.the<org.jetbrains.kotlin.gradle.targets.js.nodejs.NodeJsRootExtension>().run {
        download = true // デフォルトの挙動 falseで既にインストールされているNode.jsを使う
        nodeVersion = "16.15.0" // ここにNode.jsのバージョン
    }
}
```

# [MUI] `<Grid xs={...}/>`みたいなやつ
`this.asDynamic()`で無理やりできます。
```kotlin
Grid {
    item = true
    asDynamic().sm = 6
    asDynamic().xs = 12
    //...
}
```
`asDynamic().component = "label"`とかもできます。
対応するプロパティが見つからなかったら、断腸の思いでこれを使いましょう。
~~Kotlin/JSの意味・・・~~

# npmパッケージの関数を自分でラップして使う

[公式](https://kotlinlang.org/docs/js-react.html#use-packages-from-npm)でも説明されていますが・・・
[usehooks-ts](https://usehooks-ts.com/)の

https://usehooks-ts.com/react-hook/use-dark-mode

を使ってみます。

## npmの依存関係を書く

```diff_kotlin:build.gradle.kts
dependencies {
    // ・・・
+    implementation(npm("usehooks-ts", "2.8.0"))
    // ・・・
}
```
## 書く
`src/main/kotlin/usehooks`みたいなディレクトリを作ってそこに入れるような感じに私はしています。
今回使用するのは`useDarkMode`なので`useDarkMode.kt`を作り、[ここ](https://usehooks-ts.com/react-hook/use-dark-mode)を見ながら書いていきます

```kotlin:useDarkMode.kt
@file:JsModule("usehooks-ts")
@file:JsNonModule

package usehooks

@JsName("useDarkMode")
external fun useDarkMode(defaultValue: Boolean? = definedExternally): UseDarkModeOutput

external interface UseDarkModeOutput {
    val isDarkMode: Boolean
    val toggle: () -> Unit
    val enable: () -> Unit
    val disable: () -> Unit
}
```
正解かはわかりませんがこのように書いたら動きました。

# CSSとかのNoneが無い！！
あります。
```kotlin:完全修飾None
web.cssom.None.Companion.none
```
です。
`Auto.auto`もあります。
```kotlin
Button{
    css { 
        display=None.none
    }
    +"みえないボタン"
}
```
# どの`document`だよ！！！！！！
これはKotlin/JSあるあるですね。
安易に`kotlin-wrappers`のバージョンを上げるとパッケージ名が変わったりして時代に置いていかれます。
```kotlin
import react.create
import react.dom.client.createRoot
import web.dom.document

fun main() {
    val container = document.createElement("div").also {
        document.body.appendChild(it)
    }

    createRoot(container).render(
        App.create()
    )
}
```

このようなよく見るコードの`document`ですが、補完で2つの`document`が出てきますよね。
```kotlin
web.dom.document
kotlinx.browser.document
```
これを間違えると、`document.body`がNullableになったり、`createRoot`で型が違うと怒られます。
先程のコードの場合は上の`web.dom.document`が正解です。
下の`kotlinx.browser.document`は使う場面あるんですかね・・？
# どの`window`だよ！！！！！！
`kotlinx-coroutines`の`Window.asCoroutineDispatcher()`を使うときは、
```kotlin
kotlinx.browser.window.asCoroutineDispatcher()
```
です。
クラス `Window`には以下の2種類あり、それぞれ別の場所からアクセスできます。
```kotlin
org.w3c.dom.Window //→ kotlinx.browser.window
web.window.Window  //→ web.window.window
```
`asCoroutineDispatcher()`は`org.w3c.dom.Window`に対して使うので`kotlinx.browser.window`です。

# [MUI] `<Button component={Link}/>` `component`が無い！
足りないものは自分で作り出しましょう。
```kotlin
var ButtonProps.component :  ElementType<*>?
    get() =  unsafeCast<PropsWithComponent>().component
    set(value) { unsafeCast<PropsWithComponent>().component=value}
//例
Button{
    component=Link
}
```