Introduction to React Hooks
A couple of weeks ago, as of the writing of this article, Dan Abramov, took onto the stage to introduce React Hooks to the React community at React Conf 2018 in Henderson, Nevada. And at first glance, I was elated for as much as it introduces new API, it makes it easy for React developers to use the same React features we have been using for years now but in a more easier and elegant way and most importantly, they don’t introduce breaking changes and are 100% backward compatible.
So what exactly are these “Hooks”?
Hooks are a new feature proposal that lets you use state and other React features without writing a class. They’re currently in React v16.7.0-alpha and being discussed in an open RFC.
🎉 That’s right, you can write a function component and have access to its local state and technically also its lifecycle methods 🎉
Motivation of introducing Hooks
Any API introductions should be backed up with a motivation or reason as to “why” and this is no different. Below are some of the reasons why;
- Currently, it’s hard to use stateful logic between components: If you have been using React for a while, you’d say that HOC and Render Props solves this problem which might be true to some extent but they do introduce some constraints and other pain points. For e.g this patterns require you to restructure your components before you use them and this can be cumbersome and make your code hard to follow. These patterns also introduce the “wrapper hell” where your components are wrapped in a long nested DOM. While this can be filtered out using React Dev tools, it’s not ideal.
- Complex components can be hard to understand: React components usually start out small but with time they become complex and big which makes them hard to follow and understand. Each lifecycle method can have a bunch of unrelated logic that makes
async
calls tofetch
some data, sets upeventListerners
and cleans up these events when the component un-mounts. Based on the complexity of your application, all these can be a bit messy and hard to follow. - Classes are confusing to both people and computers: Classes can be confusing to new React devs and in fact it’s one of the hinderance that some people are reluctant to learn React. In order for you to use classes you have to understand how
this
works and you have tobind
your methods in the constructor which can be a bitverbose
Classes don’t get minified very well by dev tools and they make hot reloading flaky and unreliable.
We think Hooks are our best shot at solving all of these problems. Hooks let us organize the logic inside a component into reusable isolated units. — Dan Abramov
Show me some code already!
Hooks have been categorized into two categories: Basic and Additional Hooks.
I am going to demo useState
and useEffect
but be sure to check the others out for they will come in hand in your development work. I will write about the other hooks in subsequent series' of articles so give me a follow so that you don’t miss out.
Alright lets dive right into it.
useState
Below is a simple controlled form input that tracks the value inputted by the user which will demonstrate useState
Explanation
We start by declaring a simple function
Component
as depicted below;
import React from "react";function App() {return ( <div className="App"> <h1>Hooks demo - useState</h1> <label htmlFor="name">Name</label> <input type="text" name="name" value=/> </div>);}
Next we import useState
from react
which does the magic for us. We use useState
is below;
const [name, setName] = useState("Mary");
- It returns a pair; the first one is the
value
and the second is theupdater
here are using the array destructuring assignment - You can pass a default value to it; in this case
Mary
which will be the default value forname
Next we want to update `name` when a user types in the input field. We do that using the onChange
synthetic event which will in turn call the setName
method. See code below;
const [name, setName] = useState("Mary");const handleNameChange = e => { setName(e.target.value);};// full code below import React, { useState } from "react";import ReactDOM from "react-dom";import "./styles.css";function App() {const [name, setName] = useState("Mary");const handleNameChange = e => {setName(e.target.value);};return (<div className="App"><h1>Hooks demo</h1><label htmlFor="name">Name</label><input type="text" name="name" value={name} onChange={handleNameChange} /><pre>{name}</pre></div>);}const rootElement = document.getElementById("root");ReactDOM.render(<App />, rootElement);
useEffect
The Effect Hook lets you perform side effects like making network requests in function components. This is the equivalent of componentDidMount
and componentDidUpdate
in React class components.
To Demonstrate this we will make a simple component that fetches and renders for Star Wars characters using the Star Wars API
Explanation
First, we import both useState
and useEffect
along with React
import React, { useEffect, useState } from "react";
Next we destructure characters
and setCharaters
as we had seen before.
const [characters, setCharacters] = useState([]);
Then we use useEffect
to make a fetch
to our Star Wars API then we use our setCharacters
function to set our state.
useEffect(() => { fetch("https://swapi.co/api/people/") .then(response => response.json()) .then(({ results }) => { setCharacters(results); // set characters in state});}, []);
You will notice that we pass a second argument to useEffect
which is an empty array
. This is an optimization to stop render
from being called every time. You can read more about optimization here
One question that experienced React developers might ask at this point is how to we perform cleanups when the component unMounts
to stop memory leaks. To do this, we return a function that does the clean up for us which could be unsubscribing
to any listeners or canceling any async
methods. If we had something that we need to clean up we’d do it like below;
useEffect(() => { fetch("https://swapi.co/api/people/") .then(response => response.json()) .then(({ results }) => { setCharacters(results); // set characters in state return () => someListener.unsubscribe();});}, []);
The full code is as below;
import React, { useEffect, useState } from "react";import ReactDOM from "react-dom";import "./styles.css";function App() {const [characters, setCharacters] = useState([]);useEffect(() => { fetch("https://swapi.co/api/people/") .then(response => response.json()) .then(({ results }) => { setCharacters(results); // set characters in state });}, []); // empty array because we only run oncereturn (<div className="App"> <h1>Star Wars charaters</h1> {characters.map((character, index) => ( <div key={index} className="card"> <h5>{character.name}</h5> </div> ))}</div>);}const rootElement = document.getElementById("root");ReactDOM.render(<App />, rootElement);
Why should I care?
Hooks allow you to write more cleaner and precise code with less boilerplate code. Below are some reactions from the community.
What Next?
Hooks are awesome there’s no doubt and I’d encourage you to use them in your new components or new projects all together. The two hooks we’ve covered here are not the only ones you can learn about the other hooks here and what’s even better is that you can build you own hooks.
P.S. If you found this article insightful, hold down the clap icon for a few seconds so that this article can reach even more people. Be sure to give me a follow on here or on Twitter so as to get updates of articles like this, cheers!