✨ Hello! ✨
In this post, I will be updating the code from an old React project. I will be converting the class (aka "stateful") component into a function (aka "stateless") component that utilizes the useState
Hook. This is by no means a comprehensive guide to the useState
Hook, but my hope is that this can be a light introduction to useState
and Hooks, and perhaps a helpful reference. Thank you for reading!
🤔 What the heck is a Hook?
If you are completely new to React Hooks, React Docs has an in-depth explanation. To summarize, Hooks are JavaScript functions that allow us to utilize the React state and lifecycle features without using class components. Hooks cannot be used in class components. Instead, they are used in function components. In this article, I will be going over the useState
Hook, but there are others built-in to React (e.g. useEffect
) and you can also make your own Hooks, but I'm not at that level of understanding quite yet 😉.
✏️ useState
syntax
I found it helpful to understand the syntax of calling useState
before getting too far, so here is a brief explanation.
To call useState
, you will write something similar to the code below inside of a function component:
const [state, setState] = useState(initialState);
Calling useState
will return two values, shown inside of the brackets in the above code. The first value (state
in the brackets above) is the current state aka "state variable." The second value (setState
in the brackets above) is a function that updates the current state. useState
only accepts one argument, which is the initial state (initialState
in the code above).
This might be confusing if you are new to Hooks, but hopefully seeing it in use in my project will provide some context.
👀 My project code (before Hooks)
Let's take a look at my Chalkboard project that uses a class component to set the state instead of Hooks. Feel free to toggle the preview panel to see how the code is rendering.
*Those of you who are seasoned in React might notice my lack of keys for the list items. In this project, that was not my focus, so I am just leaving them out for now.
🪄 Let's switch it up
Below is all of the code I changed in order to utilize the useState
Hook.
Note that the original code that uses a class component is in white, while the updated code that uses the function component with the useState
Hook is in color.
1. Importing
In a class component, we import Component
from React:
import React, { Component } from "react";
With the State Hook, we instead import useState
from React:
import React, { useState } from "react";
2. Initializing state
Class components allow us to use the setState
method, which is built-in to the base Component class. Without Hooks, you need to "extend" the React Component's features to your class component. In this case, my component is called Chalkboard
. You will also notice that in order to initialize state in the class component, it needs to be written as an object:
class Chalkboard extends Component {
state = {
chalk: "",
notes: []
};
When using Hooks, you do not need to use a class component, and can instead write your component as a function component (still capitalizing the first letter of the component's name so React recognizes it!). In order to initialize state in a function component, you will call the useState
Hook. This is where the syntax I talked about before comes in! In my code below, my current state aka "state variable" for the chalk is chalk
; the function that I will use to update the state is called setChalk
; and the initial state that is passed to useState
is an empty string ""
. The same logic is followed with the notes
state:
function Chalkboard() {
const [chalk, setChalk] = useState("");
const [notes, setNotes] = useState([]);
3. Updating state
In class components, we use this.setState
to update the state:
updateChalk = (event) => {
this.setState({ chalk: event.target.value });
};
In function components, we will use the function defined when we initially called the useState
Hook. Additionally, functions within the component need to be defined with const
:
const updateChalk = (event) => {
setChalk(event.target.value);
};
Below is another event handler. This has a few more lines of code than the updateChalk
handler that need to be updated. In class components, we need to use this.state
to make changes to the state:
updateNotes = (event) => {
event.preventDefault();
var newNotes = this.state.notes.slice();
newNotes.push(this.state.chalk);
this.setState({
chalk: "",
notes: newNotes
});
};
I removed this.state
from the lines of code referencing it, and used the setChalk
and setNotes
functions instead of this.setState
:
const updateNotes = (event) => {
event.preventDefault();
var newNotes = notes.slice();
newNotes.push(chalk);
setChalk("");
setNotes(newNotes);
};
4. Rendering the UI
Class components require a render()
method to return JSX. Inside of the render()
method, the notes
variable maps over the notes
array and is later rendered in the return statement:
render() {
var notes = this.state.notes.map((note) => <li>{note}</li>);
return (
<div className="App">
<form onSubmit={this.updateNotes}>
<input
type="text"
placeholder="type here"
value={this.state.chalk}
onChange={this.updateChalk}
/>
<input type="submit" />
</form>
<div className="board">
<h1 className="chalk">{this.state.chalk}</h1>
</div>
<ul className="notes">{notes}</ul>
</div>
);
}
Function components do not have the render()
method, so the notes
variable needs to be changed a bit. Because it is no longer in a render()
method, the variable name needs to be changed to something that hasn't already been declared. In this case, I have updated it to notesList
. I also removed all instances of this.state
in the return statement:
const notesList = notes.map((note) => <li>{note}</li>);
return (
<div className="App">
<form onSubmit={updateNotes}>
<input
type="text"
placeholder="type here"
value={chalk}
onChange={updateChalk}
/>
<input type="submit" />
</form>
<div className="board">
<h1 className="chalk">{chalk}</h1>
</div>
<ul className="notes">{notesList}</ul>
</div>
);
🥳 That's it!
Here is the CodeSandbox of my updated project (with Hooks!).
⚡ Final thoughts
Converting my old project from a class component to a function component with Hooks definitely helped me understand how to use useState
in the future! I like that it requires less code, and not needing to use this.state
is great. The biggest adjustment I had to make was understanding how to use the setChalk
and setNotes
functions to update the state rather than this.setState
.
I hope this was a helpful introduction to the State Hook. Thank you for reading!
Top comments (6)
Thank you Sheila!! I'm glad it was helpful 😁 Good luck with the sticky notes project!
Fantastic article McKenna! You did an amazing job explaining the updates!
Thank you!!!!
This is AMAZING and VERY THOROUGH McKenna, well done! I will definitely be using this as a reference when I'm ready to tackle hooks myself!
Thank you! I am hoping to start posting a technical blog once a week moving forward 🤞🤞🤞
mayfever.crowdfundhq.com/users/sya...