✨ 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...