React Hooks: useState
Before I knew that React Hooks had even existed, I used to read advise like, "Always use functional components instead of class components in React." Which means always declare your components as functions instead of as classes. Or in code:
//use
const Component = ()=>{
// return code here
}
//instead of
class Component extends React.Componet{
render(){
// return code here
}
}
I tried to follow that advice for a little while. However, the moment I wanted to use state
in my component, that advice seemed useless. I had to refactor my code and use a class component instead of a functional component. I thought that was the only way to use state
or any of the lifecycle methods in React. Little did I know.
I then learned about Hooks, and that advice started to make a lot more sense.
The first few things that I have learned about React Hooks are:
1- Hooks allow us to use state
and other features without having to write a class.
2- We only call them from functional components.
3- We only call them at the top level, not inside loops, conditions, or nested functions.
let us write a simple class component that changes the background color of a div
element and then see how we can refactor it to use the useState
hook.
class App extends React.Component {
constructor(props){
super(props);
this.state= {
backgroundColor: "lightblue",
}
}
changeBackgroundColor = ()=>{
this.setState({ backgroundColor: getRandomColor() })
}
render(){
return(
<main>
<div
style={{backgroundColor:this.state.backgroundColor }}
className="circle"
/>
<button onClick={this.changeBackgroundColor}>Change Color</button>
</main>
)}
}
const getRandomColor = ()=>{
return "#" + Math.random().toString(16).slice(2,8);
}
That looks like a lot of code for something that does nothing but randomly change a background color, right?
Let's see the changes that will happen when using the useState
hook.
import React, { useState } from 'react';
const App =()=> {
// 1
let [backgroundColor, setBackgroundColor] = useState("lightblue");
const changeBackgroundColor = ()=>{
// 2
setBackgroundColor(getRandomColor())
}
return(
<main>
{/* 3 */}
<div
style={{backgroundColor:backgroundColor}}
className="circle"
/>
{/* 4 */}
<button onClick={changeBackgroundColor}>Change Color</button>
</main>
)}
First, we replaced four lines of writing a constructor and using this.state
with just one line.
// Old code
constructor(props){
super(props);
this.state= {
backgroundColor: "lightblue",
}
}
// New code
let [backgroundColor, setBackgroundColor] = useState("lightblue");
Second, we don't have to use this.setState
to update the state
variables anymore.
// Old code
this.setState({ backgroundColor: getRandomColor() })
//New code
setBackgroundColor(getRandomColor())
And finally, we no longer have to get confused by using lots of this
and this.state.<variable_name>
// Old code
onClick={this.changeBackgroundColor}
style={{backgroundColor:this.state.backgroundColor}}
// New code
onClick={changeBackgroundColor}
style={{backgroundColor:backgroundColor}}
Let's take a closer look at this line of code:
let [backgroundColor, setBackgroundColor] = useState("lightblue");
What do you think this line does? And what if we wanted to change, let’s say, the font-family instead of the background-color, what do you think would change?
Answering the second question first, if we wanted to change the font-family we would write:
Let [fontFamily, setFontFamily] = useState("Arial"); // setting Arial as the initial value of the font-family.
//Or
Let [font, setFont] = useState("Arial"); // you can name your variables whatever you want.
Back to our first question. What do you think that line of code does?
let [backgroundColor, setBackgroundColor] = useState("lightblue");
That line does three things, actually.
1- It declares a variable named backgroundColor
.
2- It gives that variable an initial value of lightblue
.
3- It declares a function named setBackgroundColor
that is now responsible for updating the backgroundColor
’s value whenever we need.
So now, why does this happen?
When we call the useState
hook and pass it a value, it returns an array of two items. The first item is a state
variable and set to the value that is passed to the useState
hook. The second item is a function that is responsible for updating the first variable.
When we write,
let [backgroundColor, setBackgroundColor] = useState("lightblue");
we use the array destruction to assign the backgroundColor
variable and the setBackgroundColor
function to the two items of the array that's returned from calling the useState
hook.
The last thing I want to mention here is that we can use the useState
hook multiple times in our components.
If we wanted to change the background-color, the font-family and the border of a component we would write something like this:
const [backgroundColor, setBackgroundColor] = useState("yellow");
const [fontFamily, setFontFamily] = useState("Arial");
const [borer, setBorder] = useState("1px solid teal");
Then use all the setBackgroundColor
, setFontFamily
, and setBorder
functions to update the background-color, the font-family, and the border, respectively.
I think that is all I know about the useState
hook so far.
Thank you for reading.
Comments