Non functional React.js
Is React.js really a functional framework? I would say no, it has an object oriented nature. Its components are declared like classes, instatiated before they are rendered, and their methods are being called in a very natural OO way.
I am not an object oriented programming fanatic, but in the latest years I have been feeling that OO is being left aside without thinking twice, just because being functional is all the rage, and I think being object oriented is one key for React’s success.
React 0.14 introduced function components that are not instantiated, they are just functions that represent what would be the render method in common components. Everybody love it and talk about it. Don’t get me wrong, I think it is a good idea, and most of my components will be functional, but the fact of encouraging only the functional use of React is what I don’t get. Nobody talks about OO React?
Object oriented React can be a really good thing, especially for creating complex reusable components.
The video player component
Let’s say I want to create the ultimate React video component. I will share it with the community and it needs to be flexible enough to to be used by every developer.
I want it to be functional (functional programming all the things!), completely controlled by the props. I will define its API:
<Video src="path/to/my/video.mp4" play={ false } />
I have added a `play` prop to easily control when the component is playing the video.
Since component’s users will have the power to decide when to play the video, and my component will have an awesome play/stop button, I will add a `onButtonClick` prop to let them decide when to start playing creating a parent component:
Creating a wrapper component to take the control it’s some more work for the developers, but I am sure that it worths the effort.
I also want the component to be able to rewind the video, that is to go to the begining of it. Or much better! I want it to go to at any time of the video! So I will add a time prop, that will play the video from that time. So if the dev want the video to go to the minute 1, needs to:
That’s nice, changing the time prop, the video is moved to that point. But what happens if the dev needs to move the video twice to the minute 1? If the `time` value is already `1:00:000` I won’t be able to detect the change from the component.
That’s happening because the component is not fully controled by the props. I set the time once to the minute 1, but then the component keeps playing the video and the time changes while the prop value is still `1:00:000`. That’s the “problem” of having uncontrolled internal state within the components. I need to let the developer completely control the time.
It won’t be hard, the time just needs to be updated every millisecond in the wrapper component:
Now the dev would have the control. The video can even be played backwards if needed… Well, that would be true if `setTimeout` executed its callback every millisecond, but it is not that way.
I think I was wrong about the time prop. Basically, a video doesn’t need to be refreshed every millisecond because it only have 50 frames per second, or 60 or 30, but never 1000 FPS. What I need is to let the developer control what frame to show! If the developer knows the frame rate, the video can be played perfectly that way!
The functional Video component is not ideal
STOP! I wanted to create the ultimate player component, to be used by everybody everywhere, but at the end, the developer would need to manage even the frame ratio to play a video. That’s not ease of use at all. I am not creating a useful component at all if its logic is outside the component. I am rather creating a template.
Actually, HTML5 video API doesn’t have a method to play a video frame by frame, but the video player is a nice example on how difficult it is to create a really reusable functional component without making the developers work too much.
React.js enforces the creation “controlled components” to handle components that manage user interaction, keeping their state under control. But a controlled component implies that any state change that affect the component must happen outside of it. They are not self-contained so they are hard to reuse, or distribute, because they force the developer to code in order to make them work.
Managing the state is probably the most important part of a React application, but sometimes it is preferable to let components manage its own internal state by themselves for the sake of the application simplicity. In these cases, the object oriented approach is much nicer than the functional one. OO components are like React.js widgets that work by themselves.
Objects hold their own state in them, and can mutate it without letting the app know, that’s why they are so much critizied. But seriously, do we need to know every millisecond at what point of the video we are? I just want to play a video, and I’m sure that it is possible to build a component that I can control and makes all the nasty work for me.
Non functional Video component
Creating a React component is nothing different than creating a `class`. The first time that our component is going to be rendered, React creates an instance of it and calls its `render` method ( and many others ). Long story short, React uses an object oriented approach to work with custom components.
We can have access to that instance using references, and that can be really useful to create our video player component.
Once we have a reference to the Video component instance we can call its methods like if we are programming with objects and classes. I will add some random but useful methods to my Video component to give the developer the control of it.
As you can see references to HTML tag return the DOM node since React 0.14 and we are able to use `video` element API.
Unlike the functional components, the methods of an OO component are thought to be used from outside. So if we want to autoplay a video with our new component it would be as easy as:
It is not that bad isn’t it? We could go to the beginning of the video just calling `this.refs.video.goToBeginning()` too.
Controlling component’s internal state
The fact that a part of our app state is hold by a component doesn’t mean that it needs to be hidden for the app. When creating any OO component it is really good to offer getter methods to know the internal state of the component. A simple `getState` method is nice to let the app know in what state.
Also a good OO React component should notify changes in its internal state, so the app can react to those changes. Object oriented components should play along with your reactive application. Let’s add a `onEnd` property to our component to let the app restart the playback when it finishes:
Offering these “event” methods as properties feels much more natural in a React development than as actual instance methods, but you can decide what fits best for you.
Having a nice API to control the internal state of OO components is essential to make them feel right in a React app. If the API is full of getter and setter methods that just get and set the internal attributes, and the component is never updating them directly, it is a sign that those internal attributes should be component’s props, managed directly by the app.
Use cases
Like the video component, any component that have some complex logic inside and is made to be reused among different applications is suitable to have a OO API.
Imagine a form component with validation capabilities. When is a good time to validate?? When the user is typing? When pressing the ‘submit’ button? Run a validation is an action, and doing actions in a declarative way, using props, is close to impossible.
With a OO approach you can create a `validates` method and let the developer run it whenever it fits best for his app.
Singleton components are also a clear example of the benefits of using an object oriented aproach in react applications.
Imagine a component to display messages to the user. These error or success toasts need to be shown for n seconds and then they should disappear from our UI. We can create an action to handle a list of toasts in our app state, push and pop messages. But why not to build a reusable component and manage the toasts for me without poluting the app state?
Summing up
Trying to create a functional video component was a really hard (close to impossible) task. In fact, HTML5 video tag is one of the best examples on how a declarative definition (the tag markup) can have a nice object oriented API in order to make it easy to use.
Object oriented and functional styles are really different ways of solve problems, but they can be used together. In order to build applications, I will always suggest the functional approach, try to make your components as dumb as possible and always keep track of the state in one place if possible. When building reusable components you can choose to create an object oriented API for them. I would even say that OO is the only option when you are building components with complex functionality.
Using an OO component, you let some part of your application state to be handled automatically by third party code. But it doesn’t mean that you lose the control of your app. If component’s API is nice you may use its methods to take the control whenever it is needed, and forget about coding for making it work.
… I’m sure this post will be disliked by lots of people :)