Here’s a story about two methods of approaching the same React-based goal. The first concerns class components, while the second concerns functional components. Both result in the same output: a dropdown list box that contains ID values. Both source from the same API. How we get to the rendered HTML, however, is different.
Class Component Method
We have looked at the class component before, although this one is more fully formed and mostly function-complete.
Lines 6-15 define the constructor, where we’re setting a state object which holds a blank array assigned to the key ids. This will hold the data we receive from the API call. It also sets up our two API callbacks, one for a successful call and one for a failed call.
Lines 20-23 are fired when the component has been instantiated. Once we know the component has rendered, we call the API.
Lines 27-31 handle a successful API call. Our data is returned in the result argument, and if the status value is “OK”, we update the state with the results from the API.
The key to this class component is that we call the API when the component has been rendered and store the data in the state. This is important because the API won’t return immediately; the render will happen before we have data. This is why we use the eval chain; if we have no data in state, something will eval to FALSE and the map function won’t be reached with an empty value. With the one-way binding of state, as soon as the state value is updated, React re-renders anything that uses that value, which will cause the eval chain to trip TRUE all the way down, rendering out our <option> tags.
Functional Component Method
Functional components aren’t as robust as class components. They’re limited to light processing duty and rendering. Prior to React 16.8, if you wanted to deal with state in a functional component, you had to pass values up the well using callbacks sent into the function as props. 16.8, however, introduced the concept of hooks. Hooks bring many of the features previously limited to class components to functions, such as state and event handlers.
Line 1 is a familiar import statement, but we are bringing in two of React’s intrinsic hooks: useState and useEffect.
Line 6 is how we set state in functional components. The first parameter is the name of the state bin, while the second is a callback we can refer to in order to update the value in state. This is a state hook because we assign useState with an empty object as it’s sole parameter. We can use a similar signature for other hooks that React defines (the discussion of which is outside the scope of this post).
Line 10-12 is the functional component equivalent of the class component’s componentDidMount event handler. useEffect is fired whenever the DOM is flushed, meaning that anything that updates the render of the component — including the contents of useEffect — will fire what’s in here. Like in our class version, we’re calling the API with two callbacks. Line 12 ends with a kind of hack; the empty array prevents useEffect from triggering itself. This is not a good way to do this, apparently, and if you want to read more about it and the proper way to stop a constant useEffect, you can check out these two articles.
Lines 16-18 comprise the API success callback, but this time we are calling setIDs, which is the function we defined back on line 6. Here, we are passing the results of the API call into the state container ids.
Finally, we render between lines 26-35. Firstly, line 29 is a much more compact way of dealing with the vague state situation than the eval chain from the class version. In fact, we don’t need to check the state at all, for some reason (both versions set a default value of ‘’). We do use map to render <option> tags here as well.
What’s the big deal? Class components seem attractive to someone like me who hails from an OOP background, even though React’s classes aren’t really OOP in the traditional sense; the structure and conventions are very familiar, though. I have always viewed functions as stand-alone workhorses that could be created when an atom of work needed to be performed but never as fully encapsulated objects that go toe-to-toe with classes.
Facebook claims that by adding hooks to functional components (and hooks can only be used in functional components), they are instantly elevated to a contender for how we can — and should — approach React components going forward. They do not suggest that React developers should overhaul their class-focused components, though, but do ask folks to consider using functional components with hooks in future code. As you can see from the examples above, functional components with hooks perform the same tasks that can be performed by class components, but with less, more readable code. The claim is that the addition of the hooks infrastructure is a negligible performance hit, considering you can potentially save on processing by simply not having to write as much code to do the same thing. You can even define your own hooks, which is not something we’re going to talk about here (because I haven’t looked into it, really).
For a much better overview of what hooks can do for your React application, check out the official introduction on the Reactjs.org website.