Function components are great, but they are limited to do exactly what they are told by way of properties. The moment you need them to be mindful of their state, you are forced to rewrite them as class components. Fortunately, a lot of class component-only features are making their way to function components.
One such feature, which is currently in alpha and is expected to land in React v16.7, is Hooks. Hooks brings statefulness and lifecycle methods, previously only available to class components to function components.
As mentioned, this feature is currently in alpha but is expected to be a part of the next point release of React. Because of this, we will need to specify a version when adding React to our project.
# Via npm
$ npm install --save react@next react-dom@next
# Or via Yarn
$ yarn add react@next react-dom@next
use
.To create a stateful function component using Hooks, we will need to initialize the state using useState
from the React package.
This method accepts a parameter to set the initial state, and returns an array containing the current state and a function to set the state.
Here’s a stateful function component that keeps track of a color that is set at random every time the button is pressed:
import React, { useState } from "react";
import { render } from "react-dom";
function StatefulFn() {
const [color, setColor] = useState(false);
function onClick() {
const colors = [
"#008F68",
"#6DB65B",
"#4AAE9B",
"#FAE042",
"#EFBB35",
"#DFA612"
];
setColor(colors[Math.floor(Math.random() * colors.length)]);
}
return (
<button onClick={onClick} style={{ backgroundColor: color }}>
Click to Change Button Color
</button>
);
}
const container = document.createElement("div");
document.body.appendChild(container);
render(<StatefulFn />, container);
The useState
method is very much intended to be used with a single value, and not a state object the way class components work. Because of this, we either have to maintain a state object manually ourselves, or more simply, just call useState
more than once to keep track of each variable in our state:
const [color, setColor] = useState(false);
const [size, setSize] = useState('medium');
const [reptile, setReptile] = useState('alligator');
Another gotcha of using function components has been their lack of lifecycle methods. Another part of the Hooks feature is the addition of useEffect
which is a combination of componentDidMount
, componentDidUpdate
and componentWillUnmount
.
In more simple terms, useEffect
will fire after the initial render and any subsequent re-renders.
If you’re familiar with the React class component lifecycle, you know that it’s bad to put code with side effects in your render method. That’s why the lifecycle methods exist to begin with.
One such side effect is firing off a network request, and then updating the state with a value that’s returned. In the next example, I’m going to simulate a very slow network connection by using setTimeout
and will display a loading message while we wait:
import React, { useEffect, useState } from "react";
import { render } from "react-dom";
function EffectedFn() {
const [loading, setLoading] = useState(true);
useEffect(() => {
setTimeout(() => {
setLoading(false);
}, 1000 * 10);
});
return (
<div>
{loading && <span>Loading...</span>}
{!loading && <span>All Done!</span>}
</div>
);
}
const container = document.createElement("div");
document.body.appendChild(container);
render(<EffectedFn />, container);
Something cool about useEffect
is that it doesn’t block the browser from updating the screen the way componentDidMount
and componentDidUpdate
do. This helps to ensure that things seem responsive and snappy to your users!
To help improve performance even further, especially when working with multiple state variables, you can tell useEffect
to only fire when a certain value has changed:
useEffect(() => {
setTimeout(() => {
setLoading(false);
}, 1000 * 10);
}, [loading]);
What’s really great about Hooks is you don’t have to use them if you don’t want to. If you’re keen on using classes, you can keep on truckin’. If you’re scared that you will need to update all of your existing, non-hooked functions, don’t be.
Hooks are 100% backwards compatible so there’s no need to scramble to update any existing code. Classes aren’t going anywhere and if/when you’re ready to start using Hooks, as long as you’re on a version of React that supports it, you can do so.
Personally, I’m sick and tired of porting functions to be classes when I need state and lifecycle support so for me, Hooks are a very welcome addition.
Plus, it’s super easy to create your own hooks or use hooks developed by the greater React community. There are already collections of available hooks that are popping up left and right.
If you’re like me and ready to start using Hooks today and want to see the code from this article in action, head over to CodeSandbox.
Thanks for learning with the DigitalOcean Community. Check out our offerings for compute, storage, networking, and managed databases.
While we believe that this content benefits our community, we have not yet thoroughly reviewed it. If you have any suggestions for improvements, please let us know by clicking the “report an issue“ button at the bottom of the tutorial.
This textbox defaults to using Markdown to format your answer.
You can type !ref in this text area to quickly search our full set of tutorials, documentation & marketplace offerings and insert the link!