Common Hooks
In this lesson we'll take a look at the most common Hooks you'll come across and learn how to use them in your apps.
Common Hooks demoed#
Arguably the most common Hooks you’ll encounter are:
useState
- which is used to interact with a component’s state.and
useEffect
- which can be best thought of as replacing the React lifecycle events such ascomponentDidMount
andcomponentDidUpdate
.
Before we move onto our big project in this module, let’s take some time to familiarize ourselves with the use of these two most common built-in Hooks.
Project setup#
We're going to introduce Create React App in the next lesson as a great way to build new React projects. For now, though, we're going to keep things simple and familiar by using Parcel JS to set up our project to bundle and run our React code for these examples.
Configuring Parcel JS#
Create a new folder and open it in VS Code. Navigate to the terminal and let’s initialize our new project:
yarn init -y
Next, let’s install the packages we need:
yarn add react react-dom
Finally, open up your package.json
file and add the following config so we can call yarn start
to run the project:
"scripts": {
"start": "parcel index.html"
},
Creating the files#
Now our project is set up and ready to run, we need to add the necessary files to our project before we fill them out.
App.js
index.js
index.html
styles.css
UseEffectExample.jsx
UseStateExample.jsx
UseStateExample.jsx
and UseEffectExample.jsx
are where we’ll do the main body of our work here, so let’s get our other files set up before we explore our example components.
index.js#
This will be the entry point for Parcel to start loading our JavaScript from. We import our main App
component here and call React DOM’s render()
method to mount it into the HTML element in our index.html
file.
import React from 'react';
import ReactDOM from 'react-dom';
import App from './App';
ReactDOM.render(<App />, document.querySelector('#root'));
App.js#
In our App
component, the main starting point for our React app, we’re using a Hook, the useState
Hook in fact.
Let’s take a look at the file in full:
import React, { useState } from 'react';
import './styles.css';
// components
import UseStateExample from './UseStateExample';
import UseEffectExample from './UseEffectExample';
export default props => {
const [example, setExample] = useState('UseStateExample');
return (
<>
<h1>Choose an example</h1>
<button onClick={() => setExample('UseStateExample')}>
useState Example
</button>
<button onClick={() => setExample('UseEffectExample')}>
useEffect Example
</button>
<div className='container'>
{example === 'UseStateExample' ? (
<UseStateExample />
) : (
<UseEffectExample />
)}
</div>
</>
);
};
Here, we’re importing our two example components, UseStateExample
and UseEffectExample
and using the example
value in state
to determine which one to show.
If example
is set to the string ‘UseStateExample' then we’ll show the UseStateExample.jsx
component, otherwise, we’ll show the UseEffectExample.jsx
component.
We also have two buttons that both call the setExample()
method to update the example
state value, which will, in turn, change which child component is displayed.
styles.css#
Much of the styles here are the same basic styles from our very first example that we built in Module 2, the Greeting App. We’ve added a couple of extra layout selectors at the bottom to add some flex box support and additional styling to some form elements, such as a select and label.
body {
font-size: 16px;
line-height: 1.4;
font-family: 'Lucida Sans', 'Lucida Sans Regular', 'Lucida Grande',
'Lucida Sans Unicode', Geneva, Verdana, sans-serif;
margin: 5em;
}
p {
margin-bottom: 1.6em;
}
input,
select {
padding: 0.5em 1em;
line-height: 1;
font-size: 18px;
border: 1px solid #ececec;
}
button {
border: 1px solid #ececec;
background: #ececec;
padding: 0.5em 1em;
cursor: pointer;
font-size: 18px;
margin-right: 15px;
}
button:hover {
background: #c9c6c6;
}
label {
display: block;
margin-bottom: 0.5em;
}
label + input,
label + select {
margin-bottom: 1em;
}
form button {
display: block;
}
.container,
.dogs-container {
padding: 0 2em 2em;
border: 1px solid #ececec;
border-radius: 4px;
margin: 1em auto;
}
.form-message {
background-color: #ececec;
border-radius: 4px;
margin: 1em auto;
padding: 2em;
font-size: 18px;
}
.dogs-container {
display: flex;
align-items: center;
justify-content: space-around;
}
.dogs-container img {
max-width: 250px;
max-height: 200px;
}
index.html#
Once again, our index.html
file simply provides us with a basic entry point for Parcel to follow and find our JavaScript starting point.
It looks like this:
<html>
<head>
<title>Hooks example demo</title>
</head>
<body>
<div id="root"></div>
<script src="index.js"></script>
</body>
</html>
With the basic files set up and ready to go, let's take a closer look at the useState
and useEffect
Hooks.
The useState Hook#
useState
is a direct replacement for the class-based state
you’ll see used in this fashion:
// updating state
this.setState({
someProperty: 'some value'
});
// using state
<p>The value is {this.state.someProperty}</p>;
As we’ve already seen in the previous module, the useState
Hook has a very simple syntax for setting and retrieving values from it.
// initial declaration
const [nameOfValue, setNameOfValue] = useState('initial value here');
// updating state
setNameOfValue('a new value');
// using state
<p>The value in state is {nameOfValue}</p>;
You’re not limited to what you can store inside this state Hook, just like you’re not limited with state
used in a class component. Any valid JavaScript primitive value, array, object, and even function can be passed into and stored in state
.
The convention is to have distinct declarations for multiple values, unless they’re logically able to be kept together, such as with form values.
// multiple values
const [itemCount, setItemCount] = useState(0);
const [data, setData] = useState([]);
const [balance, setBalance] = useState(null);
// grouped values
const [formValues, setFormValues] = useState({
name: '',
email: '',
message: ''
});
In the first group, you can see that we've got singular values such as an integer, '0', an empty array, and a null
value. These are all distinct pieces of state
and declared in their own variable pairs, each using a separate call to useState
. However, for the formValues
variable, we're calling useState
and passing in an object with multiple properties, one for name
, email
, and message
, that each represents a form field value.
We could have also separated these values out into their own useState
call like this:
const [name, setName] = useState('');
const [email, setEmail] = useState('');
const [message, setMessage] = useState('');
This is fine and you'll see this approach quite frequently. As with a lot of things in development, there is a lot of personal preference and trade-offs on how you tackle a problem and implement a solution. For me, it makes sense to group closely related slices of data, such a collection of form field values, into a single place (i.e. the formValues
variable above), but it does add a little more overhead in dealing with updates to any particular form field's value. Conversely, if you have a really large form with a lot of field values, breaking each one into a separate call to useState
could potentially create a lot more code for you to manage and a very large component.
With the explanation in the bag, let’s build a little example app to demonstrate how to use useState
and the sorts of values it can be used with.
First things first: open up the UseStateExample.jsx
file, where we’ll need to import React and create the empty component’s skeleton:
import React, { useState } from 'react';
const UseStateExample = () => {
return <></>;
};
export default UseStateExample;
We want to take a look at how to effectively use the useState
Hook here. To do that, we’re going to build an HTML form that will update values in our component’s state, and display a nice message to our user once they’ve submitted the form.
To do that, we’ll need a few things:
An object in
state
to track our state valuesA value in
state
to determine if we should show the message (i.e. has the form been submitted?)Methods to handle changes in the form elements and form submission
An HTML form
Our component’s looking a little bare at the moment, so let’s fill it out.
This page is a preview of Beginner's Guide to Real World React