In this article, you will explore React Hooks, a new feature in React’s latest version 16.8. React Hooks are functions and serve as a modular replacement for state and lifecycle methods. Instead of class components, React Hooks allow you to build functional-based components.
To complete this tutorial, an understanding of React is required. To learn more about React, check out the How To Code in React series.
useState()
MethodIn a class component, you would import React into an index.js
file and create an instance of a class object JustAnotherCounter
. You would add a state and a function to update the property count
:
import React, { Component } from 'react';
class ScoreCounter extends Component {
state = {
count: 0
};
setCount = () => {
this.setState({ count: this.state.count + 1 });
};
render() {
return (
<div>
<h1>{this.state.count}</h1>
<button onClick={this.setCount}>Count Up To The Moon</button>
</div>
);
}
}
In your render
lifecycle method, you would return the value held in state and a button that invokes your function through each click.
Let’s compare your ScoreCounter
class component as a functional component.
With React Hooks, you can condense your state and lifecycle methods into a functional component in your index.js
file with fewer lines of code. Import useState
into a destructured object:
[label index.js]
import React, { useState } from 'react';
function ScoreCounter() {
const [count, setCount] = useState(0);
return (
<div>
<h1>{count}</h1>
<button onClick={() => setCount(count + 1)}>Count Up To The Moon</button>
</div>
);
}
The useState()
method destructures your state object into an array and assigns its elements the value of invoking the hook. The first element is the state, while the second is a function that operates as the .setState()
method. The argument you pass into the useState()
method acts as the initial state value, here the number 0
as your counter. You can pass in any data type such as arrays, objects, strings, and numbers as the initial state value.
With each click of your button, the setCount()
function passes in your state as an argument that increments by 1
.
Now, your ScoreCounter
functional component supports less syntax in favor of code readability.
You can also use the useState()
method multiple times in the same function. In your index.js
file, import useState
and declare the functional component Login
:
import React, { useState } from 'react';
function Login() {
const [username, setUsername] = useState('');
const [password, setPassword] = useState('');
return (
<div className="login">
<form>
<label>
Username: <input value={username} onChange={event => setUsername(event.target.value)}/>
<br />
Password: <input value={password} onChange={event => setPassword(event.target.value)}/>
</label>
<button>Submit</button>
</form>
</div>
);
}
The Login
functional component employs the useState()
method multiple times to define and set a username and password in a form, and outlines logic for each input
field.
With an understanding of useState()
, let’s consider other React Hook methods.
useEffect()
MethodReact Hooks introduces the useEffect()
method to replace a class component’s lifecycle methods componentDidMount
, componentDidUpdate
, and componentWillUnmount
. The method also allows side effects in your functional component, such as changing content in the document object model and fetching data. useEffect()
will run after every component render.
Let’s compare a class’s lifecycle method call with a functional component.
In your index.js
file, import useEffect
into your ScoreCounter
component:
[label index.js]
import React, { useState, useEffect } from 'react';
function ScoreCounter() {
const [count, setCount] = useState(0);
useEffect(() => {
console.log(count);
document.title = `Your new score is ${count}`;
});
return (
<div>
<h1>{count}</h1>
<button onClick={() => setCount(count + 1)}>Count Up To The Moon</button>
</div>
);
}
Here, useEffect()
produces the side effects of logging into the console to check for the initial state value in count
, and updating the document object model.
Since useEffect()
runs each time a component renders, you can set a second argument, an array, to store each instance and call on the method if a value has changed.
In your index.js
file, apply an empty array as the second argument to your useEffect()
method:
[label index.js]
import React, { useState, useEffect } from 'react';
function ScoreCounter() {
const [count, setCount] = useState(0);
useEffect(() => {
console.log(count);
document.title = `Your new score is ${count}`;
}, []);
}
With each render to your ScoreCounter
component, the useEffect()
method will store each instance of count
in the array and update the component if the value differs from a previous call. In one call, useEffect()
combines the functionality in the componentDidMount
and componentDidUpdate
lifecycle methods.
To simulate the componentWillUnmount
lifecycle method, return a function in the useEffect()
method in your index.js
file:
[label index.js]
import React, { useState, useEffect } from 'react';
function ScoreCounter() {
const [count, setCount] = useState(0);
useEffect(() => {
console.log(count);
document.title = `Your new score is ${count}`;
return () => console.log(`Component is unmounted`);
}, []);
}
By declaring and returning an anonymous function, the useEffect()
method unmounts a component in one call, here with a console.log
to check for its status.
To fetch data, pass fetch
within useEffect()
to get information from an external API.
In your index.js
file, import useState
and useEffect
. Declare a GitHubUsers
functional component, and pass in fetch
within the body of useEffect
:
import React, { useState, useEffect } from 'react';
function GitHubUsers() {
const [user, setUsers] = useState([]);
useEffect(() => {
fetch('https://api.github.com/users')
.then(response => response.json())
.then(data => {
setUsers(data); // set users in state
});
}, []);
Notice the second argument set as an empty array. This is to inform useEffect()
to run once. The useEffect()
method will invoke fetch
to call the GitHub API and set the response into a JSON object.
Once the call is successful, include a return statement in your GitHubUsers
component to iterate through the data and output the GitHub user information:
return (
<div className="section">
{users.map(user => (
<div key={user.id} className="card">
<h5>{user.login}</h5>
</div>
))}
</div>
);
}
The useEffect()
method takes the functionality within all three of a class component’s lifecycle methods in one call to log into the console, update the document object model, and fetch data from an external API.
The useState()
and useEffect()
methods are powerful additions to the React library. Now with React Hooks, you can maximize your functional components with state and lifecycle methods in shorter lines of code.
For more information on React Hooks, check out the How To Manage State with Hooks on React Components article.
Thanks for learning with the DigitalOcean Community. Check out our offerings for compute, storage, networking, and managed databases.
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!
Nice tutorial!
In function GitHubUsers() … should the state variable name be “users” instead of “user”? Seems like it to me (newbie).
function GitHubUsers() { const [users, setUsers] = useState([]);