In this guide, we'll take a look into useState by comparing class and function components.
This isn't an in-depth look as there are other great features of the useState hook that aren't included in this guide.
What Are Hooks?
React hooks are functions that allow us to access state and lifecycle methods in functional components without having to write a class component.
Prior to hooks, the only way to access the state was by using a class component. Functional components were purposed for handling anything UI related without logic. You may have heard them called "stateless functional components" or "presentational components".
Let's Dive In
I've created a small project that displays two planets using React Kawaii. For the given planets, you can toggle their mood by clicking the Emotion Toggle button.
Class Component
import React, { Component } from 'react';
import { Planet } from 'react-kawaii';
class PlanetClass extends Component {
state = {
emotion: true
}
handleToggle = () => {
this.setState(prevState => ({
emotion: !prevState.emotion
}))
}
render() {
const { emotion } = this.state
const emotionCondition = emotion ? 'blissful' : 'ko'
return (
<>
{<Planet size={250} mood={emotionCondition} color="#FDA7DC" />}
<button
className='emotion-btn'
onClick={this.handleToggle}
>
Emotion Toggle
</button>
</>
)
}
}
export default PlanetClass
Above, our component has a single state named emotion
with an initial value of "true". Following this, we have a method called handleToggle
that takes the initial state and provides the opposite.
The handleToggle
method then gets attached to the onClick
event handler within our button, allowing us to click the button and toggle between the emotionCondition
.
The emotionCondition
is a condition that takes the initial state of emotion: true
and provides a property of "blissful" if true otherwise "ko" if false.
Please note that I've used the Class Fields syntax in this class component. This allows me to write property instances directly within the class and eliminates the need to create a constructor and call super (my favorite). If you want to learn more about the Class Fields syntax, I'd highly suggest reading this article by Tyler Mcginnis.
I am also using an arrow function for the handleToggle
method to avoid binding methods in the constructor since arrow functions have their own "this".
Functional Component
import React, { useState } from 'react';
import { Planet } from 'react-kawaii';
const PlanetHook = () => {
const [emotion, setEmotion] = useState(true)
const handleToggle = () => {
setEmotion(prevState => !prevState)
}
const emotionCondition = emotion ? 'blissful' : 'ko'
return (
<>
{<Planet size={250} mood={emotionCondition} color="#61DDBC" />}
<button
className='emotion-btn'
onClick={handleToggle}
>
Emotion Toggle
</button>
</>
)
}
export default PlanetHook
At first, you'll notice our functional component using hooks has significantly less code (rubs hands together).
Let's break this down and go over the changes while comparing what we had before.
Within the first line, we've imported useState
as a named export from 'react'.
import React, { useState } from 'react';
Let's move down to line five where we've called useState
.
const [emotion, setEmotion] = useState(true)
This single line is what makes our function stateful.
We have two elements within an array, emotion
and setEmotion
. Both are being destructured (array destructuring) and will be the return value of useState
. Within the parenthesis of useState
, we store the initial value of our state.
Confusing? We'll go further.
Within the array the first value will be the name of the state and the second will be the setter for the state. Both can be named anything, but it's common practice to include "set" followed by the state name as the setter (second value).
setEmotion
is the equivalent of setState
in a class component.
Let's take a quick glance at the state in the class and function component.
// Class Component
state = {
emotion: true
}
// Function Component
const [emotion, setEmotion] = useState(true)
Comparing the two, we have a few things that don't inherently change.
-
state
anduseState
are both keywords that dictate state - the name of our state (
emotion
) remains - the value of our state remains
The key differences in useState are:
- We don't store state within an object literal
- We use destructuring to name our state and state setter
- Our state value is written within the parenthesis following the
useState
keyword
How Do I Set State?
Remember, the second value of the array is the setter. We'll use that when updating state. Check out both methods for the class and function component.
// Class Component
handleToggle = () => {
this.setState(prevState => ({
emotion: !prevState.emotion
}))
}
// Function component
const handleToggle = () => {
setEmotion(prevState => !prevState)
}
Above, our class component uses setState
followed by an object literal within a callback.
In our function, we call setEmotion
with the desired updated state.
Both are using callbacks since we are setting state based on a previous state. Also, setState
in React is actually asynchronous. This means that after calling setState
, the state variable itself may not change right away so it's best to use a callback.
Is that all?
Of course not, there's always more. For now, I'll see you next time and bring useEffect with me.
Top comments (0)