Let's dive into the frontend. Connecting that newly developed backend service, and present that data via ReactJS.

Caveats

I would like to raise some caveats. While I will show end to end consumption of an API. I would not recommend using this in production, as a full solution. By this I mean that I would recommend you develop components in Kotlin. Then bind them together in a Javascript frontend. The ecosystem is still under heavy development. We can compile and develop perfectly fine, but the third party libraries are still being developed.

An example of this is Relay and GraphQL. While this is seemingly the ideal way to develop React components. The relay type bindings, have not been cast to Kotlin yet. At least not that I am aware of. So for this introduction we will be utilizing the standard REST endpoints. Bringing this higher level it's like writing a React application in type script. While TypeScript is great, it generally lags behind flow on the React side.

Directory Structure

Full disclosure I have not run a React application in production. So this may be off base. Despite that you can use this guide to get a working React skeleton.

web/src/main/kotlin/design/animus/kotlinmultiplatformskeleton/
└── web
    ├── components
    │   └── demotable.kt
    ├── director.kt
    ├── pages
    │   ├── base.kt
    │   └── home.kt
    └── typealiases.kt

  • Components Are individual components your application is broken down into. Think an Avatar, User Card, etc.
  • Pages Pages are the target points for routing.
  • Director Our main function (Director is my standard, name it as you please.)
  • Type Aliases Are the common type aliases that we will utilize.

Let's Build a Base Page

Notes

We will be using

  • My MaterialUI Bindings.
  • My JS XMLHTTPRequest Bindings

The base page is meant to wrap around all other pages. It will provide the skeleton application menu, and core design and themeing.

Yes MaterialUI isn't for everyone but I have horrid design skills. I will be covering Kotlin Style in a future post.

Defining State

Much with like flow or type script. We define a type or interface for the state of a component. The type definiton, casts properties to the type they may contain. THis interface will be provided to the componetn. So when we access state.$property it is cast to the proper type.

interface PageBaseState : RState {
    var drawerOpen: Boolean
}

To start we implement a state for the BasePage. This will contain a side menu, that is opened and closed upon clicking a hamburger menu. The property drawerOpen will be used to set the attribute whether the drawer is opened.

class PageBase : BaseComponentWrapper<RProps, PageBaseState>() {

    fun handleDrawerChange(event: Event) {
        setState { drawerOpen = !state.drawerOpen }
    }

    fun initState() {
        setState {
            drawerOpen = false
        }
    }

    fun RBuilder.drawerItems() {
        MenuList {
            MenuItem {
                routeLink(to = "/") {
                    Icon { +"home" }
                    +"Home"
                }
            }
        }
    }

    override fun RBuilder.render() {
        val drawer = Drawer {
            attrs.variant = "persistent"
            attrs.open = state.drawerOpen
            attrs.anchor = "left"
            IconButton {
                attrs.onClick = { event -> handleDrawerChange(event) }
                Icon { +"chevron_left" }
            }
            drawerItems()
        }
        div {
            AppBar {
                Toolbar {
                    attrs.disableGutters = !state.drawerOpen
                    IconButton {
                        attrs.onClick = { event -> handleDrawerChange(event) }
                        Icon { +"menu" }
                    }
                    +"KotlinMultiPlatformSkeleton"
                }
            }
            (1..4).map { br {} }
            Grid {
                attrs {
                    container = true
                    alignContent = "center"
                    alignItems = "center"
                    justify = "center"
                    spacing = 16
                }
                props.children()
            }
        }
    }
}

We are implementing a PageBase component here. For any component that has state we will call the initState function. This is defaulting the drawerOpen to be closed state.

The main Render function will build a core div element. That wraps around an AppBar, this will be a constant at the top of our application pages. Using the inbuilt range syntax of Kotlin to add 4 break points between teh app bar. Then setting up the Grid layout. Finally we call props.children Which will render any child elements.

Aside

A page is a wrapper of the single application page model. Think of /about, /faq, /products. Each of the pages will call the base page component like.

PageBase()  {
    Grid {
        attrs.item = true
        MagicalPageComponent()
    }
}

This ensure the header, footer, menu etc. Wil be propigated down to each page. This can also be amended to have a base parallax, jumbo, or other type of page.

End Aside

The last thing we need to do is add this to the RBuilder extension function.

fun RBuilder.PageBase(children: RBuilder.() -> Unit) {
    child(PageBase::class) {
        children()
    }
}

This allows the component ot be called from any render function.

The Home Page

class Home : RComponent<RProps, RState>() {


    override fun RBuilder.render() {
        PageBase {
            Grid {
                attrs {
                    xs = 12
                    md = 12
                    item = true
                }
                Card {
                    CardHeader {
                        attrs.title = "Welcome to Kotlin Multi Platform Skeleton"
                        attrs.subheader = "A react demo with material-ui"
                    }
                    CardContent {
                        Typography {
                            +"""
                            This project utilizes react and kotlin. To build a simple
                            web application. Giving you an over view of state management
                            in react. As well as props. Have a look at the source code, and
                            hit us with a pull request if you have any questions.
                            """
                        }
                        Divider {}
                        Typography {
                            a {
                                attrs.href = "https://animus.design/about/"
                                +"By: Animus Null"
                            }
                        }
                    }
                }
            }
            Grid {
                attrs {
                    xs = 6
                    md = 6
                    item = true
                }
                Grid {
                    attrs.container = true
                    Grid {
                        attrs.item = true
                        Button {
                            attrs.color = "primary"
                            attrs.onClick = { _ -> window.open("https://gitlab.com/AnimusDesign/KotlinMultiPlatformSkeleton/issues/new") }
                            +"Open an Issue against Kotlin Multi Platform Skeleton"
                        }
                    }
                    Grid {
                        attrs.item = true
                        Button {
                            attrs.color = "primary"
                            attrs.onClick = { _ -> window.open("https://gitlab.com/AnimusDesign/KotlinReactMaterialUI/issues/new") }
                            +"Open an Issue against Kotlin React Material UI Bindings"
                        }
                    }
                }
            }
        }
    }
}

Above is the sample of how we lay out a home page. With nested grids. Everything is run as a lambda/closure. There are a few on click elements here. The basics to understand are.

  • Definition of interfaces for component and props.
  • Manipulating state.
  • Exposing the Component to the RBuilder functions.
  • Composition of basically html.