Functional programming on frontend with React & ClojureScript

Functional programming on frontend with React & ClojureScript

Functional programming on frontend with React & ClojureScript

Introduction

I have been working and evaluating popular JavaScript frameworks such as AngularJS, Polymer, Ember and also emerging WebComponents for quite some time. In this blog post I will show advantages of React way of building scalable and well performing web applications with taste of functional programming.

In this tutorial we will introduce basics of ClojureScript as well and show how React plays nicely with ClojureScript through one of its wrappers called Reagent. Working app is included as well.

What makes UI hard ?

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 – high level overview

What is React ?

React is addressing the aforementioned challenges in a very neat and profound way. React authors define it as a JavaScript library for creating UIs and addressing problem of building large applications with data that changes over time. As already stated, mutable state is very complex thing to manage and reason about. So how is React approach to managing UI state different compared to others frameworks and libraries out there ?

Functional programming to the rescue

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.

React basics

Now let’s see what React does in the browser with DOM. Diffing between tree representations is done internally by React through indirection mechanismcalled 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.

React – JavaScript code sample

https://gist.github.com/pjazdzewski1990/fa6b6fd58f96593a8d01

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 getInitialStatemethod. 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 purein 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 getDefaultProps method. In this example, properties are passed via JavaScript syntax extension called JSX that looks similar to HTML and can be found at the very bottom of code sample and also in render method. React provides tools that translate this JSX syntax into native JavaScript.

Reasons for introducing JSX syntax are that it is more familiar for casual developers such as designers and brings natural way of expressing larger trees of components.

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:

https://gist.github.com/pjazdzewski1990/7f9a8b42a0b3fea78eb0

This syntax shows how it is possible to compose component trees in very readable and intuitive way. JSX transformer takes care of replacing XML literals with proper native JavaScript calls.

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 componentWillUnmount getDefaultPropsgetInitialStatecomponentDidMount, 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.

React meets ClojureScript

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 seeks to address the weak link in the client/embedded application development story by replacing JavaScript with Clojure, a robust, concise and powerful programming language. In its implementation, ClojureScript adopts the strategy of the Google Closure library and compiler, and is able to effectively leverage both tools, gaining a large, production-quality library and whole-program optimization. ClojureScript brings the rich data structure set, functional programming, macros, reader, destructuring, polymorphism constructs, state discipline and many other features of Clojure to every place JavaScript reaches.

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 – simple React wrapper

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:

https://gist.github.com/pjazdzewski1990/a8f69e42d1baee8146be

This component can be mount to DOM node like this:

https://gist.github.com/pjazdzewski1990/265cc5d711748ae84d8e

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.

https://gist.github.com/pjazdzewski1990/a904186382add967c428

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.

https://gist.github.com/pjazdzewski1990/54b4b725806e7fd4eae1

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.

https://gist.github.com/pjazdzewski1990/98ef2328f50f597ae944

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!.

Call to swap! accepts function as argument that is applied to value of atom and stored.

https://gist.github.com/pjazdzewski1990/d7e1517845b8f1f34ed2

Those are the basic building blocks of Reagent which will enable you to build well performing UIs.

A word about performance

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.

Sample app

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.

Pexeso walkthrough

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.

https://gist.github.com/pjazdzewski1990/4f27ebaa26d33e5c6534

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:

https://gist.github.com/pjazdzewski1990/f848c8849cae92d951ec

[Source code]

: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:

https://gist.github.com/pjazdzewski1990/2aa0a8545a5e25ff2ec7

Main UI showing cards is very simple, it is basically grid of cards that allows card to be revealed by simple click.

https://gist.github.com/pjazdzewski1990/26e0c77f879e4481ac65

[Source code]

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 ;.

https://gist.github.com/pjazdzewski1990/382cd3aaa7d3360f21cc

[Source code]

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.

Summary

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.

ClojureScript has matured into production-ready language and it allows build better, more reusable and solid frontend code in functional manner and with fewer lines than in native JavaScript.

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.

Links

Do you like this post? Want to stay updated? Follow us on Twitter or subscribe to our Feed.

Read also:

Download e-book:

Scalac Case Study Book

Download now

Authors

Marek Tomas

Latest Blogposts

04.04.2024 / By  Aleksander Rainko

Scala 3 Data Transformation Library: ducktape 0.2.0.

Scala 3 Data Transformation Library: Ducktape 2.0

Introduction: Is ducktape still all duct tape under the hood? Or, why are macros so cool that I’m basically rewriting it for the third time? Before I go off talking about the insides of the library, let’s first touch base on what ducktape actually is, its Github page describes it as this: Automatic and customizable […]

28.03.2024 / By  Matylda Kamińska

Scalendar April 2024

scala conferences april 2024

Event-driven Newsletter Another month full of packed events, not only around Scala conferences in April 2024 but also Frontend Development, and Software Architecture—all set to give you a treasure trove of learning and networking opportunities. There’re online and real-world events that you can join in order to meet colleagues and experts from all over the […]

14.03.2024 / By  Dawid Jóźwiak

Implementing cloud VPN solution using AWS, Linux and WireGuard

Implementing cloud VPN solution using AWS, Linux and WireGuard

What is a VPN, and why is it important? A Virtual Private Network, or VPN in short, is a tunnel which handles all the internet data sent and received between Point A (typically an end-user) and Point B (application, server, or another end-user). This is done with security and privacy in mind, because it effectively […]

software product development

Need a successful project?

Estimate project