Skip to content
This repository has been archived by the owner on Apr 20, 2023. It is now read-only.

bnorm/kotlin-react-function

Repository files navigation

kotlin-react-function

Maven Central

Warning This library has been archived and no future work is planned. kotlin-wrappers has made it significantly easier to define functional components since this compiler plugin was created. Also, Compose for Web exists and provides a similar code style this compiler plugin was attempting to achieve.

Writing functional components with Kotlin/JS for React is great but requires a bit of boilerplate which makes each new component require some setup. Most of this boilerplate is extremely simple, perfect for automation.

Introduction

Consider the following Kotlin/JS DOM builder function:

fun RBuilder.Hello(name: String) {
    +"Hello, $name"
}

This function adds text to the DOM but does not support any React hooks because it is not currently a React functional component. To do so requires a fair amount of boilerplate:

private external interface HelloProps : Props {
    var name: String
}

private val HELLO_COMPONENT = fc<HelloProps>("Hello") { props ->
    +"Hello, ${props.name}"
}

fun RBuilder.Hello(name: String) {
    child(HELLO_COMPONENT) {
        attrs.name = name
    }
}

With the Kotlin compiler plugin provided by this library, making the original function a React component is as simple as adding an annotation! (and Gradle dependency stuff)

@RFunction
fun RBuilder.Hello(name: String) {
    +"Hello, $name"
}

The compiler plugin automatically generates the Props interface and the functional component property. It then rewrites the original function to add the component as a child and automatically assigns all the component property attributes. Basically doing all the boilerplate for you automatically! Magic!

Work In Progress

This library is a work in progress and requires using Kotlin/JS IR backend for compilation and often requires a specific version of Kotlin as well. The Kotlin/JS IR backend is currently in preview and is not recommended for production. Use at your own risk!

Kotlin Version Plugin Version
1.4.10 0.2.1
1.4.20 0.3.0
1.4.30 0.4.0
1.5.0 0.5.0
1.5.10 0.5.1
1.5.30 0.6.0
1.6.10 0.7.0

See the sample directory for a working project using this compiler plugin which is also available live.

Gradle Plugin

Builds of the Gradle plugin are available through the Gradle Plugin Portal.

plugins {
    kotlin("jvm") version "1.6.10"
    id("com.bnorm.react.kotlin-react-function") version "0.7.0"
}

Annotations are automatically included, but if they are needed separately, the dependency is available via Maven Central:

implementation("com.bnorm.react:kotlin-react-function:0.7.0")

Make sure Kotlin/JS is configured to compile using IR!

kotlin {
    js(IR) {
        // ...
    }
}

Advanced Topics

Component Key

To set the key of a React functional component, use the @RKey annotation on a single parameter to a @RFunction annotated function.

@RFunction
fun RBuilder.ListItem(@RKey item: Item) {
    ...
}

This uses the toString() value of the annotated parameter as the key for the component. If the value of the key needs to be controlled more explicitly, mark an unused parameter as the key.

@RFunction
fun RBuilder.Component(... other parameters ..., @RKey key: String) {
    // `key` doesn't need to be used to be set as the key of the component
}

If the @RKey annotated parameter is null, then the string "null" will be set as the component key. It is also possible to use default parameters to derive the key from another parameter.

Generics

The @RFunction annotation supports functions with generics.

@RFunction
fun <T> RBuilder.GenericList(items: List<T>, onItem: RBuilder.(T) -> Unit) {
    div {
        for (item in items) {
            onItem(item)
        }
    }
}