Converting a Complex React Native Class Camera Component to Hooks: Part I

Simon Stern
The Startup
Published in
4 min readSep 16, 2019

Interested in React Native E2E testing? Subscribe at https://detoxdemystified.net/

If you’re a React Native developer and haven’t used hooks yet, you should definitely take the time to check them out. Hooks allow you to use state and other react component features without using a class. This also leads to simplification of components, sometimes leading to really elegant looking solutions. After refactoring some pretty hardcore class-components into beautiful, stateful functional components with hooks, I’m convinced they’re the future of React. No more confusing this.someHandler.bind(this), or verbose this.setState({}). In fact, between context and hooks, and tools like Amplify, React Native has never been more fun, and rapidly developing new components/applications has become a really fast process.

To illustrate the power of hooks, I decided to take on the challenge of refactoring a small camera component, <RNCamera />, into a functional component with hooks. Through this transformation we’ll highlight some common hooks, and be able to compare the two approaches.

Before we begin, I just want to emphasize that there is no right or wrong when comparing class components with functional components. If you prefer class components, don’t feel the pressure to adopt! This article is simply meant to highlight how hooks can be used to write some of the same things.

So, let us begin with our <Camera /> Component. If you’ve seen a few class-based components before, this should look pretty familiar. We have our class declaration, our `componentDidMount(), a ref, and a setState call. Take some time to go over this component and really pick apart what makes this uniquely a class. That exercise will really help when it comes time to refactor.

Now, this will be a bit challenging, since we can’t really test it until its complete, but if we approach it systematically, we can have a decent looking functional component and debug any issues from it until it works. Let’s begin!

Step 1: Use State, mate

We have our familiar constructor initializing a bunch of variables which are used throughout the component. We can replace these with useState, which essentially gives our component access to mutable local state. This is my favorite hook, the easiest hook, and I think one of the most powerful. Being able to manipulate local state has long been the domain of class-components…until now!

We’re going to first import useState from React, and then declare our components state as an object of this type. The code looks like so:

This is not necessarily the only way to do this. This object can be imported from a store or context, (using useContext of course), or you can treat the components entire state as a single object. With useState, making sure you are calling the setter method whenever the state needs to be changed.

Try this out, and go ahead and and replace every this.setState with its analog useState call.

Step 2: Be Effective

Ok! State is taken care of. Now let’s replace our componentDidMount(). This method is called when the component first mounts to the tree, and in this case is important for validating whether the correct permissions are in place before anything else happens with the camera. We can replace this with useEffect , another important hook which essentially replaces componentDidMount() and componentDidUpdate(). UseEffect is often misunderstood and an abstraction that people generally find troublesome. We’re going to implement useEffect at the top of our component in place of componentDidMount() to perform the task of checking for those permissions when the component first renders. Don’t forget to include the empty array as your second argument! And if you expect your local permissions values to change on this component, you can even scope the useEffect function to run every time they do. Pretty powerful!

Step 3: C’mon ref thats a brutal call!

We’re almost there! Our functional, stateful, hooks-based component is almost ready. Our last major player here is the ref which is attached to the camera component. Declare the ref, initializing it with a null value. Then, in the component itself, point towards the ref and voila, it’s really that easy. Just make sure to remember that the useRef object has a .current property which represents the initialized to the value you passed (ref’s man).

Step 4: Clean up, buttercup

We’ve implemented our hooks and accounted for all the differences between a class and functional component, so we are basically almost done! At this step, you want to make sure you’ve removed all traces of the this keyword. You should also make sure you’ve removed the render() method as well. After all that work though, we’re finally ready to try out our new component. With any luck, you should see something like this:

Beautiful, absolutely beautiful. Let’s also take a moment to compare our code. Opinions may vary, but I much prefer the second approach to developing components. I find it to be less cluttered and much easier to debug. Semantically, its also much more approachable to beginners/juniors and I think thats really important.

I’d like to thank the React Team for their hard-work on building the hooks functionality, and everyone who took the time to read this! I hope it was as much fun for you to work through as it was for me to write :)

Simon Stern is a freelance software developer and part-time instructor. If you’re looking to build React Native apps, or interested in his consulting services with hooks, React Native, or AWS, drop him a line at https://simonstern.ca

--

--