Lately all of my frontend work at ScalaC projects was done mostly using React. Recently lot of companies started to adopt this powerful framework. Since we are Scala shop and fans of functional approach as well as interested in using other functional languages I decided to give a try to ClojureScript and see how it might play together with React. In fact, those 2 technologies are playing together very nicely and enable you to build scalable and well performing UIs in functional way.
One of the biggest and most common problems (not only) in the frontend web development is state management. In order to manage state of UI developers and frameworks have to come up with strategies for keeping DOM in sync with its view and DOM representation. Since users can interact with web app UI in many ways, managing state transitions is quite a challenging task to be done right when we have to consider good user experience, performance and keeping complexity of underlying codebase as low as possible. Growing complexity comes up with more bugs which are mostly direct result of managing changes in application state. Such codebase is also harder to test and reason about which adds up to development costs.
React brings the very basic essence of functional programming to the table. It provides abstractions such as components which are basically (pure) functions and get you away from imperatively touching the DOM.
Basically, in terms of functional programming, you write idempotent, composable functions. Data is coming to your functions as input which emit tree like representations as return values. When data changes, functions are re-run again with new data as input. React diffs the result of previous function call with new one and it effectively calculates the difference between the tree structures. From higher level perspective, React is a function which takes two DOMs and generates a list of DOM operations to be applied to the DOM, i.e., it is referentially transparent.
Now let’s see what React does in the browser with DOM. Diffing between tree representations is done internally by React through indirection mechanism called virtual DOM which mirrors the real DOM. Every time when input data changes new virtual DOM is generated and only differences between them are translated into batch operations applied to real DOM, in the most effective way possible. This results in higher performance and sheds you away from touching the DOM by hand, which might results in bugs.
In React you work with Components which are reusable, basic building blocks of UI. You simply update component internal state and then its UI is re-rendered accordingly. You do not have to deal with programming state transitions by hand which results in reduction of code complexity. Let’s see some practical code example to explain the idea of React components little bit more.
This is example of stateful component. To allow reuse of components each of the components has its own unique state accessed via
this.state. When using stateful components, initial state is defined through
getInitialState method. In case component’s state changes (next timer tick in this example), markup will be updated by re-invoking
render() function. In order to keep up with FP principles and get advantage out of them, this function should be pure in general i.e. should not depend on anything other than component state & properties and generate any side effects.
This component renders itself also based on already mentioned properties. Properties are immutable data that turn dull components into configurable interface elements. In component instance they are accessed via
this.props. Similarly as for state, it is possible to define default properties via
Declaring hierarchy of components that should be returned as a result of calling
render function on some arbitrary component might look for example like this:
React API also provides possibility to hook in your code in methods executed at specific points of component lifecycle. In case of Timer example we use getDefaultProps, getInitialState, componentDidMount, componentWillUnmount and render lifecycle methods.
React makes rendering of UI as simple as defining a function. Since React follows principles of the functional paradigm, it is no surprise that the ClojureScript community has embraced React with open arms. In next chapter of this blog post we will have a look at ClojureScript and one of its React wrappers called Reagent and will get our hands dirty with building sample app.
For those of you who are not much familiar with ClojureScript, I strongly recommend to read rationale which contains nice summary of what is ClojureScript about:
ClojureScript is a simple language that favors a functional style of programing and is based on small numbers of fundamental concepts. For those exposed mostly to imperative, object-oriented languages some of the concepts might seem unfamiliar at first glance. However, learning those concepts gives you another powerful programming tools to your hands.
Another specific thing about ClojureScript is its syntax which mimics Clojure (Lisp dialect). Instead of going through syntax and basics of the language here in this blogpost I rather recommend you to go through this concise guide of ClojureScript which I found very helpful.
After grasping basics you should be ready to read and comprehend code samples in the following chapter. ClojureScript syntax actually enables you to write very concise representations of component hierarchies using Reagent library. I found Reagent to be the simplest and most intuitive ClojureScript wrapper to start with. I recommend you to watch out for Om which gets lot of attention these days and bundles few great ideas together as well.
Reagent is a library that provides minimalistic interface between React and ClojureScript. It allows you to define React UIs of arbitrary complexity using only plain ClojureScript functions & data and describe it using Hiccup-like syntax which is very concise and easy to read. Your application is built together only using bunch of very basic but powerful concepts.
Let’s see how to define basic component using Reagent:
This component can be mount to DOM node like this:
Component composition is done in a very easy and concise way. You can also define accompanying CSS classes to components and pass children components as params as you do in React.
In ClojureScript, almost everything is immutable. To accomplish mutability ClojureScript uses concept of atoms. Atoms are references to objects which needs to be dereferenced in order to obtain object instance. Think about them as similar thing as pointers in C.
Common and viable practice is to define all of your application state in one atom which might be done like this.
Manipulating atoms is done through side effecting functions (suffixed with !). Reagent uses it’s own version of atom. Any component that uses an atom is automagically re-rendered when it’s value changes. This allows for more complex binding scenarios than in typical use of React. Distinction between props and state is gone and you are free to use Reagent atoms in any way you prefer. Let’s revisit our Timer component - this time little bit simplified.
Number of elapsed seconds is kept in its own atom - in this case unique state of component. Most common way to mutate atom value is to use built-in ClojureScript function
swap! accepts function as argument that is applied to value of atom and stored.
Those are the basic building blocks of Reagent which will enable you to build well performing UIs.
React itself is very fast. Reagent is able to be even faster because of optimizations done in ClojureScript. All of the actions that might trigger re-rendering components (dereferencing atom, changing args passed to component or its state) benefit from fast pointer comparisons between changed ClojureScript data structures and trigger re-rendering of components only when it is really needed. This means you have to care about performance rarely (for example when displaying long list of items) and define UI as you feel fit.
By grasping basics and knowing benefits of using ClojureScript and Reagent together you should be ready to understand code of sample basic application Pexeso. Whole source code can be found on GitHub and you are encouraged to follow and experiment with this example.
You can see working demo deployed on Heroku as well.
To showcase Reagent together with ClojureScript I created a sample application Pexeso. This game is also known as Memory, in this case simplified and meant to be played by one player. Player in game basically reveals 2 cards with symbols in one step, if symbols match he scores and has to guess other pairs of matching cards. Point of this sample application is to explain basics of working with Reagent & ClojureScript.
In this blogpost I won’t go into details of setting up a ClojureScript project. The project requires Leiningen build tool and you will need to have it installed before continuing.
Most convenient option for you (if you are Mac user) might be to install it using brew package manager.
I decided to use excellent Reagent Leiningen template for projects using Reagent. This template packages everything needed for production ready ClojureScript applications. It comes up with nice development environment that allows you to do instant subsecond builds of your whole app and see them immediately swapped in the browser resulting in very efficient workflow for learning and trying things out.
Whole application logic except template stuff has around ~100 lines of code. Let’s go through most important parts of it.
We will start by defining global state that keeps track of cards and value of last revealed card:
:last-symbol value is compared to symbol of recently revealed card. If match of symbol occurs, card state atom present in
:cards  vector is updated.
Card state is represented by map with keys described below. After clicking on card with symbol “M” card state is updated into following map:
Main UI showing cards is very simple, it is basically grid of cards that allows card to be revealed by simple click.
You might wonder about
doall function that wraps for comprehension. Point here is that we have to eagerly evaluate lazily generated sequence of atoms that hold cards’ state. Otherwise Reagent would be unable to dereference them properly which would lead into inconsistencies. State of the card is then passed as an argument to function creating React components. Internals of component can be followed by reading the comments starting with ;.
That is pretty much all worth elaborating that relates to logic of the game. Whole source is available and commented throug on GitHub and I encourage you to try to implement some basic features - such as number of steps done to complete the game or even try to come up with feature that enables you to replay steps of finished game.
As you can see picking up the stellar combo ClojureScript + Reagent is very simple and requires very little code to get things done. Things like atoms simplify your life and enable you to create more complex binding schemas. Functional code makes your frontend code easier to reason about and might be even more performing than your current implementations using plain React.
I believe you might greatly benefit from using those technologies while building sophisticated web applications. If you are interested in ClojureScript and have been looking at it from distance I hope that I piqued your interest and wish you good luck in your learning endeavours.
Feel free to express your questions, comments or opinions in the blog post comments section down below.