The functional side of React
In the React environment, every piece of a UI is a component. Components can be composed together to create other components. The application itself is a component: a composition of components. The developer approaching React is naturally led to think of it in terms of Object-Oriented Programming. The syntax itself to define a component promotes this idea:
However, under the Object-Oriented dress, React hides a functional nature. Let’s find out how.
Rendering an output
The main constraint for a React component is to implement a render() method. A component without a render() method is not a React component. The render() method returns a React element, that is the component’s markup defining its appearance. In other words, React is requiring that any component must have an output. This could make you think of a component more in terms of a function than of an object: a component is something that returns an output based on an input.
Components as functions
Actually, not only you can think of React components as functions. You can implement them as functions. The following code shows how to implement with a function the component we defined above:
As you can see, it is a simple and compact way to implement the component.
In addition, you can pass arguments to the function, as in the following example:
You passed the props argument, that is just the props object used to pass data from one component to another.
Immutability of props
As you know, props are immutable, you can read them but you cannot change them. This is one of the aspects that moves React components towards a truly functional approach. Since props are the input argument of a component, granting their immutability avoids side effects. In fact, this is a fundamental rule in functional programming: no input argument must be changed by a function. This is one of the basic principles to create pure functions.
Unidirectional data flow
Another feature of the React environment is unidirectional data flow. This means that in a component’s hierarchy, data must flow from the higher up component towards the lower component, not vice-versa. This concept may require a little effort if we think of components as objects. Instead, it should be quite natural if we think of the components in terms of functions. Unidirectional data flow is just the effect of function composition.
Consider the following code:
It describes two components: the App component using the Hello component to show the Hello React! text. It also defines an implicit hierarchy between the App and the Hello components. However, at a first sight, it is not so clear the unidirectional flow of the name property’s value.
Now, consider the following version of the same code:
It should appear clear that the component hierarchy is nothing but the composition of the function App() and the function Hello(). You could think of it as the following:
The passage of the value from App to React and not vice versa should be more evident.
Composition vs Inheritance
In the Object-Oriented programming paradigm, it is natural to think of inheritance as a mechanism to specialize a class. However, if you think of React components in terms of functions, this approach is not so natural.
For example, suppose you want to specialize your Hello component so that it also shows a welcome message. You can simply create the new component by composing it with the Hello component, as in the following example:
As declared by the Facebook team, rarely you need inheritance.
Higher-Order components and Higher-Order functions
A Higher-Order component is a common pattern in React programming. It allows reusing a component logic to create a new component. In simple terms, a Higher-Order component is a function that takes a component as input and returns a new component as its output. The following is an example of a Higher-Order component:
The function AddWelcome() takes the GreetingComponent argument and uses it in the render() method of a new component definition, TheNewComponent. This new component simply adds a welcome message after the output of the GreetingComponent. Finally, it returns the new component.
You can use this function as in the following example:
You get a new component by applying AddWelcome() to the Hello component.
You can translate the previously seen implementation of the AddWelcome() function into a function-based approach as follows:
As you can see, this is not but a Higher-Order function, that is a function taking another function as input and returning a new function as output.
Components and the state
The state of an application is the set of data that changes over time. The functional programming paradigm aims to avoid the use of the state in an application. In fact, the application state management is one of the main sources of complexity in the software development. However, since you cannot do without it, at least you should try to limit its use and to make it more manageable.
React’s development guidelines promote the creation of stateless components, that is components not using the state property. This should grant that the output of a component only depends on its props. A stateless component looks a lot like a pure function, and indeed it is.
However, you know you cannot write a meaningful application without using the state. The trick is to isolate the state in a few points of the application, better if in one point. This strategy corresponds to the pattern that asks the developer to use the state in the higher component in a component hierarchy. In other words, a component hierarchy should have in its root a stateful component, while its descendants should be stateless components. This way, we can better control the state since it is managed by a single component in the hierarchy.
Unlike what might seem at first glance to developers approaching React for the first time, this library promotes more Functional-Oriented than Object-Oriented tenets. In general, this allows writing more formally verifiable code, for example with automatic tests, and more reliable applications. I suggest to make the most of the functional features of React to write more maintainable code.
Andrea Chiarelli is the author of Beginning React.