Writing React apps with Idris

React is a Javascript framework for writing web apps. Like Flutter, its approach to building GUIs is almost purely functional. Let's look at how one could use React with a purely functional language.

I picked Idris because it's a purely functional language with an easy-to-use Javascript backend. Syntactically, it's similar to Haskell and Purescript. It has a rich standard library but we won't use it in this small experiment.

The main function is very simple. The app argument is a function and we also pass a state to the runApp function.

total main : IO ()
main = do
    runApp $ app $ MkState 0

The state of the app is defined by the following record:

record State where
    constructor MkState
    count : Int

It has only one property, count. The MkState constructor is used in the main function to create the initial state instance.

The app function builds the app:

total app : State -> App State
app state = do
    MkApp state $ \context => mkDiv [
        mkH1 "React with Idris",
        mkDiv "Clicked \{ (getState context).count } times",
        mkButton context "Click me" (\state => { count := state.count + 1 } state)
    ]

The state argument is the initial state. The function returns an instance of the generic App type, which is used by the runtime to build the DOM.

The MkApp constructor takes the initial state and a function that creates the structure of the app. For example, mkDiv represents the <div> element in JSX and mkH1 represents the <h1> element.

The mkButton function is slightly more complex because it uses an anonymous function, which is used when the user clicks the button. In this app it creates a new state with the count property increased by one. The runtime then updates the UI.

Below is the complete code of the app:

module Main

import React

record State where
    constructor MkState
    count : Int

total app : State -> App State
app state = do
    MkApp state $ \context => mkDiv [
        mkH1 "React with Idris",
        mkDiv "Clicked \{ (getState context).count } times",
        mkButton context "Click me" (\state => { count := state.count + 1 } state)
    ]

total main : IO ()
main = do
    runApp $ app $ MkState 0

The Javascript FFI can be found on GitHub and the bare-bones result on GitHub Pages.

ReactFunctionalIdris
Avatar for Petr Homola

Written by Petr Homola

Studied physics & CS, PhD in NLP, interested in AI, HPC & PLT

Loading

Fetching comments

Hey! 👋

Got something to say?

or to leave a comment.