React for Rubyists: Simple React/Redux todo app written in Ruby

Technology

Adam Mazur Full-stack Developer

Why?

Everyone that knows me is aware that I don’t like Javascript. Another well-known thing is that I love Ruby. When I discovered React I found it a great solution for nowadays client-side applications. The idea behind component-based approach allows developer to isolate and atomise elements of the app. The biggest downside of React (apart of it is written in JS) is that it introduces JSX. This in not something that we were fighting for. For the last few years we have been trying to find the best way to separate HTML from JS and CSS, to separate business logic layer from presentation layer and now JSX combines everything together.

So the idea of React is great, but the solution isn’t perfect. I was wondering why we can’t combine Ruby which is smart and elegant with React? One of the reason why we can do that is that React is object-oriented. You create a template of a component (class) and then you create many instances passing some parameters. JS is not for OOP. In Ruby everything is an object, though. It seems like a perfect match.

How you can run Ruby in the browser?

Directly you can’t. The same way as ES2016, ES2017, CoffeeScript and TypeScript. We use all of them. Why? Just because most of us feel under the skin that JS syntax isn’t perfect. So we have transpilers like Babel to compile from JS to JS. Ruby has it’s own compiler — Opal.

Opal is a Ruby to JavaScript source-to-source compiler.
It comes packed with the Ruby corelib you know and love.
It is both fast as a runtime and small in its footprint. — Opal creators

Ok, so we get rid of JS. Now we have to face the problem of JSX. Here the HyperLoop with HyperReact comes!

HyperReact is a wrapper for the React.js library for creating user interfaces. HyperReact provides all the goodness of React combined with the expressiveness of the Ruby language.

This is exactly what we need. HyperReact provides a very simple DSL for creating components classes. Let’s have a look at the example:

Isn’t it more elegant? Right, we got all the tools. Let’s build something.

Simple Todo App

That will be a very simple and limited version of the Todo app, cos it will only allow you to list tasks and add new. This is because I only want to show how it works.

Task Class (ToDo)

First, let’s create very simple class for representing a single task (todo). Nothing special.

Task Component

What I like in React is that you can focus on a single component in isolation. We need display single task, so no matter in what context we will use the task, it should look and work the same way (unless we want it).

I’m a fan of bottom-up approach so let’s start from the single task component.

 

Very simple component for very simple purpose. As you can see here we pass todo as a parameter and it is an Object which matches ruby object.

Task List Component

Now using the component above we can create a component that lists all the tasks.

You can think of it as about microservices. They have a single responsibility and utilises other microservices.

Form Component

The first feature is ready. Now let’s add a form that will allow to input new tasks.

You can spot some new elements here. define_state lets us define internal state of the component. In fact it’s an instance variable — nothing less, nothing more. Basing on the state and how it changes React builds VirtualDOM.

We don’t implement `add_todo` method here. Instead we pass the method as a parameter. This is to separate the presentation layer from business logic. Form component is a place for inputs and buttons. Presentation elements only.

ToDo Box

Right, we have all the components. All created above are dump-components. They are don’t know much how the whole app works. They are isolated and simple. Now we need one smart-component a.k.a. container. This component has some logic and create instances of dump-components. It is a common practice to call them boxes. Here is our ToDoBox :

You can see that this is still very simple and elegant. We have a renderblock that uses dump-components and add_todo method that implements adding new task to the list. To explain the implementation of add_todo we need to stop here and talk a little bit about client-side application state.

Application state

It’s pretty straightforward that application state is an data set that identifies in which state the application is at the moment. We don’t have it in Rails apps, cos they are stateless. As client-side applications started to grow managing the state of the app has became a big issue. One of the most popular solution today is Redux which works great with React.

Redux comes with a very simple model. We have one state for the whole app which is immutable (read-only). We can change the state only by making some actions/events (f.e. sending a form, clicking a button).

Here is a great animation that shows the flow of Redux:

Redux flow

We have following elements:

  • Store — home for the current state, Reduces and Dispatcher
  • Reducer — which produces new state of the app basing on actual state and the action the came from the Dispatcher
  • Action — operation that should be done on actual state (f.e. add_todo), is based on an app event (f.e. button click, form submit)
  • Dispatcher — takes the action and pass it to the reducer. It works like a Rails dispatcher.

Here is the simple and full implementation of Redux store for our application:

The most important thing here is the reducer method which is the heart of the store. It defines how the state should change if the store will receive add_todo action.

Let’s get back to our ToDoBox and the implementation of `add_todo` method.

We tell the store to dispatch action add_todo with id and body as additional parameters (which reducer implementation knows how to use).

Once reducer will receive the action, it will produce new state (not change, co remember it’s immutable) and React will do the job and refresh the view. User will see his newly created task on the list.

Running the app

We’ve got all the components and the store. Let’s run our application:

After requiring stuff needed we create store object and initialise it with an empty array. Then we create a lambda function that renders our smart-component. On document ready event(thanks to elegant Opal JQuery DSL) we subscribe for store changes, so store will re-render (using React magic tricks with VirtualDOM) our component on changes. Finally we call the render function to initialise the view.

Summary

We created a very simple and limited todo app to show basic ideas behind React and Redux using Ruby and its Opal and HyperLoop libraries. If you want to see the application in action and get into the details of how to run it in the browser please see the full code on Github. You can fork it and write more features. Thank you for your time and hope to see you soon!

Our app up and running

Further reading