Functional Components with React stateless functions and Ramda

What you need to know:

  • A bit of functional programming (compose, curry, lenses)
  • A bit of React
  • A bit of ES6

Note: I will use JSX notation to simplify the code samples.

What is a React stateless function?

Usually you may define a React component as follows:

Or using the ES6 class syntax:

Or using a plain JavaScript function! Did you know?

A quote from the React documentation:

This simplified component API is intended for components that are pure functions of their props. These components must not retain internal state, do not have backing instances, and do not have the component lifecycle methods. They are pure functional transforms of their input, with zero boilerplate. However, you may still specify .propTypes and .defaultProps by setting them as properties on the function, just as you would set them on an ES6 class.

And again:

In an ideal world, most of your components would be stateless functions because in the future we’ll also be able to make performance optimizations specific to these components by avoiding unnecessary checks and memory allocations. This is the recommended pattern, when possible.

Pretty interesting right?

The React community seems to be more focused about the Class or the classic createClass approach, let’s do some experiments with stateless components.

App container

First thing first let’s build an App container component as a function that accept an app state object:

Then define a render method as a property of the App function:

Wait a moment! Why do we need a curried render method that leverage on ReactDOM.render? And why are render method parameters (node and props) in a different order? For now the only explanation needed here is that, since we are using stateless components that are pure functions to their props, state must be managed elsewhere. In other words state must be managed externally and passed down to the components as props. Let’s see a concrete example by building a timer.

Stateless Timer component

A simple timer component that will accept only one prop secondsElapsed:

Add it to App:

Finally create a main.js file and start rendering!

Before explaining what’s going on here, let me say that mutating the appState like I did in appState.secondElapsed++ make me feel very bad but later on we will write some kind of reducing function for that kind of stuff.

So what we can understand now is that render is just syntactic sugar for making continuous re-rendering of a component with new props, the line:

const render = App.render(document.getElementById(‘app’));

Will return a new function with this signature:

(props) => ReactDOM.render(...)

No rocket science here! Any time we want to react to a change of the state we can re-render as we did with setInterval:

setInterval(() => {
appState.secondsElapsed++;
render(appState);
}, 1000);

Each second secondsElapsed property gets incremented and render is called within the updated appState.

Now we will implement a reducing function in a Redux style for incrementing the value of secondsElapsed. A reducing function must not mutate the current state and at a very simple implementation has the following signature:

currentState -> newState

And here we have our incSecondsElapsed reducing function implemented using Lenses from Ramda:

First of all we created a Lens:

const secondsElapsedLens = R.lensProp('secondsElapsed');

In simple words a lens is a way to keep the focus on a given property without specifying on which object, they are cool because of their reusable nature. So if we apply a Lens against an object we can:

  • View
R.view(secondsElapsedLens, { secondsElapsed: 10 });  //=> 10
  • Set
R.set(secondsElapsedLens, 11, { secondsElapsed: 10 });  //=> 11
  • Set by applying a given function
R.over(secondsElapsedLens, R.inc, { secondsElapsed: 10 });  //=> 11

Our incSecondsElapsed reducer is the result of the partial application of R.over. This line:

const incSecondsElapsed = R.over(secondsElapsedLens, R.inc);

Will return a new function that, once called within our appState, will apply R.inc on the lensed prop secondsElapsed.

It is worth noting that Ramda never mutate objects, we still have to do the dirty job:

appState = incSecondsElapsed(appState);

If you want to support undo/redo you could easily implement by yourself a history array where to push new app states or you could use Redux.

Until now we have seen few stuff about currying and lenses, let’s experiment with compose.


Compose React stateless functions

The first time I read about react stateless components I wondered if I could R.compose such functions. The answer was, obviously, yes :)

Let’s start with a React component that will print a todo list, using the React.createClass approach:

Now the question is: TodoList can be represented as a composition of more smaller reusable parts? Yes, we can split it into 3 smaller components:

  • A container
  • A list
  • And a list item

Now, one step at time, try to understand the output of the following scenarios before seeing the solution below each one:

Until now nothing too fancy we are passing the result of ListItem(TodoItem) as a parameter to List and again, the result of List(ListItem(TodoItem)) as a parameter of Container.

Let’s do the same exercise as above but by using composition, try to understand the output of the following scenarios:

Here we are! A TodoList component can be expressed as the composition of a Container, a List and a ListItem:

const TodoList = R.compose(Container, List, ListItem);

Wait a minute something is missing! As of now our TodoList function can only accept a single todo object, this is wrong, we want to map over an array of todos and print them:

Can we simplify the mapTodos function in a more functional style?

Tadaaaa! The full source code of the TodoList component:

One last little thing is missing, let’s see what is in a minute, before we will:

  • Mock some todos in the appState
let appState = {
secondsElapsed: 0,
todos: [
{id: 1, text: 'Buy milk'},
{id: 2, text: 'Go running'},
{id: 3, text: 'Rest'}
]
};
  • Import TodoList and add it as a child of the App component:
import TodoList from './todo-list';
const App = appState => (<div className="container">
<h1>App name</h1>
<Timer secondsElapsed={appState.secondsElapsed} />
<TodoList todos={appState.todos} />
</div>);

TodoList expect an array of todos as input but here:

<TodoList todos={appState.todos} />

We are passing the list as a prop, that’s the same as we are calling the component like this:

TodoList({todos: appState.todos});

We must modify the TodoList in order to make it accept an object and get the property todos:

const TodoList = R.compose(Container, List, R.map(ListItem), R.prop('todos'));

No magic here! Just right to left composition, R.prop(‘todos’) will return a function that, once called, accept an object and return the property named ‘todos’ which is an array that gets passed to R.map(ListItem) and so on… :)

That’s all guys! I hope you find this article(?) in some way useful, this was just a part of some experimentations I’m making with React and Ramda. In future posts I will try to cover Higher Order Components and try to transform React stateless functions through Transducers!

Note: any kind of feedback will be very appreciated, even for proper grammar checks as I am not a native a speaker :)

Here you can find the full source code: https://github.com/mirkodrummer/react-stateless-components-ramda

Arrivederci!