React JS and functional programming are related in many ways.
In React, we build small components where each component is only responsible for doing one thing. By treating components as building blocks for other components, we build bigger and more complex components. In the end, a React application can be imagined just a hierarchy of components. Functional programming shares this same idea. We build a complex function by assembling smaller and more simple functions and glue them together though function composition. With proper patterns, an entire application can built in this way and in the end is more modular and easier to reason about.
What I feel that is still missing is some guidance on how to write React life cycle functions like render(), componentDidMount(), etc in a more functional and declarative way. The purpose of this article is to fill that gap.
To learn about functional programming and point-free style, it’s easy to start. All you would have to do is starting with the following 2 links. Follow whatever links the first one takes you too. Recently, he has been writing a book too.
I am just trying to show here how to apply what is discussed by DrBoolean (Brian Lonsdorf) to building a small but real React application.
First, we examine how to write React form code in a functional and declarative way. In the main page (which is called main.jsx as we will see), there is a simple form:
Type the name of a Github user, then click on the Search button or hit the Enter key. Sounds simple but it’s important that we allow form submission by hitting the Enter key or else the user experience is not a pleasant one. When the form is submitted, the application routes the request to another component which calls Github APIs. If there is a Github user with that name, the application shows a dashboard page. Otherwise, we see the same page with the error message.
If only the space bar key is hit or nothing is typed at all, and then the Search key is clicked or the Enter key is hit, the form must NOT be submitted, but the input text must regain focus and the text input field must reset.
To start, as alluded earlier, we first create a file called main.jsx. Forget about form submission for a second, let just create a form. The only thing required is to implement the render() method (note that I said method and not function). How can the render() method which receives no input argument whatsoever be pure? I think the point is that render() should get its input from this.props and this.state and returns a single element as long as it does not modify the component’s state. I’d like to highlight this fact by writing a anonymous function in render(), invoke it right away by passing this.props, this.state and the component itself, and return its result. The outline or skeleton of the code looks something like:
While the render() method does not look functional, the anonymous function inside it does.
By the way, as you examine my code, you will rarely see any semi-colon and the keyword function anymore.
The render() code that returns a React element for the form above is shown partially below:
The above code is totally pure. As much as the JSX makes things look very busy and complicated, the code does not rely on any external data or the environment and does not cause any side effect. The two functions displayUserName and displayError are curried and just waiting for their one and only input (which is props.data which in turn refers to the userName). They are both point-free, which means they do not require the argument to be specified. Note that ‘argument’ in the previous sentence is singular because curried function only awaits one single argument.
When displayUserName is called with the input argument props.data which holds the userName, R.ifElse compares userName against null. If it’s null, it returns a function that returns an empty string, or else returns a function that returns the userName. The function displayError works in the same way.
So far, the code above is very static and does not address any interaction from the users. Let’s incorporate the onSearchClick() function (line 11 above).
Pause for a moment and appreciate this beauty. Everything inside the function onSearchClick() is declarative and point-free.
Remember that context is an argument that gets passed to the anonymous function. Since onSearchClick was bound to it, the this keyword inside onSearchClick refers to the React class. Therefore we can get to the element in the back-in instance element of the DOM (or is it virtual DOM?). When the Search button is clicked, we have to grab the text that was typed in the input text field. We do this according to React documentation
var element = this.refs.searchText.getDOMNode()
The next 2 lines (line 4 and 5) in the function would cause side effects. The side effects, respectively, are to manipulate the DOM and to route to a different page. It is inevitable and expected that when a button is clicked, some side effects would happen. Otherwise the application would be a boring one. What’s important here in this function is we ‘quarantine’ these functions in its own area.
The next 4 lines are 4 pure functions.
var getInput = element => element.value
var isInputEmpty = R.eq(‘’)
var checkInput = R.compose(isInputEmpty, R.trim, getInput)
var handleClick = R.ifElse(checkInput, focusElement, showResult)
They represent the notion that we build small and simple functions and glue them together to make bigger functions. Put these 4 functions together, their logic is pretty simple as explained below:
Check if the input text field, after getting trimmed, is empty. If so, reset the input text field and put the focus on it. Otherwise, route the application to the route represented by /dashboard/userName
Finally the line of code that kicks thing off
The following diagram shows the logic flow of the onSearchClick function (1 through 6) and the input argument to each function (in red parentheses) as if these functions are not point-free.
The function onKeyDownHandler works very much in the same way but is slightly more complicated than onSearchClick. In addition to having to check for input text field equal to empty string (after trimmed), it also has to check for the key down equal to the Enter key.
And the diagram to help explaining how logic flows and where arguments are passed if the functions are not point-free.
Routing is carried by react-mini-router. There’s not much to do with functional programming in route.jsx.
From the file route.jsx, it’s clear that the React component <Main /> can be called with the userName or null. This is the argument in props inside the render method.
The Dashboard component makes use of the Lenses and Future functors. Both are explained by DrBoolean. I also discussed about Lenses here. Now about Future. At some point, the application has to make calls to Github APIs. The Ajax calls to Github APIs are async, hence the use of Future functors. In React, to make an Ajax call, we are supposed to do so in the componentDidMount() and not in the render() method. This is according to React documentation which discussed this pattern and that’s what we follow here.
Future functor which includes the function fork() above works similarly to Ramda’s R.isElse.
The render() method should look familiar to the one in main.jsx. In componentDidMount(), the application makes an async call to Github API. While waiting for the result, render() is called with state.isLoading equal to true. The <Spinner /> component is rendered. If state.isLoading is false, dashboard calls the component <Github />.
The component <Spinner /> contains no logic. Its render() method is very straightforward.
Github, Repos, ReposList
The remaining 3 files github.jsx, repos.jsx and reposList.jsx are more of the thing. They should be very easy to reason about because everything done in those components are patterns that we have discussed here so far.
Again, you can find the repo for the code here.