Kotlin~MPP~ 【フロントエンド React編】

# Kotlin~MPP~ 【フロントエンド React編】

# 概要
公式のチュートリアルをしてみたのでそのまとめです
[Create React Kotlin App](https://github.com/JetBrains/create-react-kotlin-app/blob/master/README-ja.md)
[公式チュートリアル](https://play.kotlinlang.org/hands-on/Building%20Web%20Applications%20with%20React%20and%20Kotlin%20JS/01_Introduction)

# 準備
以下をダウンロード
npm [Download/Install](https://www.npmjs.com/get-npm)
yarn [Download/Install](https://yarnpkg.com/lang/en/docs/install/#mac-stable)
IntelliJ IDEA [Download/Install](https://www.jetbrains.com/idea/download/?_ga=2.171642530.364102357.1573703413-1728893455.1570294821#section=mac)

# プロジェクト作成
```bash
$ yarn create react-kotlin-app <プロジェクト名>
```

# 最初のページ作成
main関数はKotlinプログラムのエントリポイントです。
main関数内にrender関数を記述します。

```kotlin:Main.kt
fun main() {
    // ここはお決まり
    render(document.getElementById("root")) {
        // <h1>Hello</h1>タグはReact.ktでは以下のようになります。
        h1 {
            // ※文字列を表示したい場合は先頭に『+』を記述する必要があります。
            +"Hello"
        }
    }
}
```

# componentの作成
クラスコンポーネント

```kotlin:MyClassComponent.kt
interface State : RState {
    var name: String
}

inteface Props : RProps {
    var text: String
}

class MyClassComponent(props: Props) : RComponent<Props, State>(props) {
    override fun MyClassComponent.init() {
        // stateの初期化
        text = "MyClassComponent"
    }

    override fun RBuilder.render() {
        div {
            h1 {
                +"${props.text} ${state.name}"
            }
        }
    }
}

fun RBuiler.myClassComponent: ReactElement {
    return child(MyClassComponent::class) {}
}
```

ファンクションコンポーネント

```myFunctionComponent.kt
fun RBuilder.myFunctionComponent(text: String): ReactElement {
    return h1 {
        +"${text} myFunctionComponent"
    }
}
```

呼び出しかた

```kotlin:Main.kt
fun main() {
    render(document.getElementById("root")) {
        myClassComponent {
            text = "Hello"
        }
        myFunctionComponent("Hello")
    }
}
```

# Styleの適用
## cssファイルを使用する場合
```kotlin:Main.kt
// main関数でrequire
fun main() {
    // src以下のcssを読み込む
    requireAll(require.context("src", true, js("/\\.css$/")))

    render(document.getElementById("root")) {
        h1("title") {
            +"Hello"
        }
    }
}
```
```main.css
.title {
    color: #000;
    fontSize: 32px;
}
```

## styled-componentを使用する場合
パッケージをインストール

```bash
$ yarn add @jetbrains/kotlin-css @jetbrains/kotlin-css-js @jetbrains/kotlin-styled inline-style-prefixer styled-components@4
```

```kotlin:Main.kt
// main関数でrequire
fun main() {
    render(document.getElementById("root")) {
        // styled + タグ名で「css{}」が使用できる
        styledH1 {
            css {
                color = Color("#fff")
                fontSize = 32.px
            }
            +"Hello"
        }
    }
}
```

## npmパッケージの使用
kotlinでjsのモジュールを呼び出すには一手間必要です。
サンプル：react-playerを呼び出す。
### jsの場合

```js
import ReactPlayer from 'react-player'
// ...
<ReactPlayer
  url={url}
/>
```

###kotlinの場合
モジュールの設定

```kotlin
@file:JsModule("react-player")

import react.*
// jsの「export default」のこと
@JsName("default")
external val ReactPlayer: RClass<ReactPlayerProps>

external interface ReactPlayerProps : RProps {
    var url: String
}
```
呼び出し

```kotlin
// ...
ReactPlayer { attrs.url = url }
```

## REST APIの使用
ブラウザのfetchを使用した場合

```kotlin
fun fetchData() {
    window.fetch("https://url").then {
        it.json().then {
            return it
        }
    }
}
```

coroutinesを使用(async/await)

```kotlin
suspend fun fetchData() =
    window.fetch("https://url")
                    .await()
                    .json()
                    .await()
```

### 感想
npmのモジュールを使用する際に一手間かかるのとHooksが使用できない（ライブラリーがあるかも？）点が少し不便だと感じました。

ただkotlinで書くので、コルーチンや型の安全性、便利なkotlin組み込み関数などが使用でき、IDE(IntelliJ IDEA)の補完やインポートが便利なため悪くないと思います。