I got a surprise introduction to hooks this week after my project partner and I integrated React Bootstrap into our React project, and even though we've worked with React for barely a few weeks, the experience actually wasn't too bad!
What are Hooks?
'Hooks are functions that let you “hook into” React state and lifecycle features from function components. Hooks don’t work inside classes — they let you use React without classes.' - React Docs
Hooks are awesome. For now I've only learned how to use just one hook, useState
(there's also useEffect
and useContext
), but I've found that it's a great solution to one of my greatest pet peeves about React, which is having to choose between using class and functional components.
Class Components are my Safe Space
For the first couple of weeks that my cohort and I spent learning how to use React, I focused heavily on fine-tuning how to structure basic class components.
I learned how to use lifecycle methods such as constructor
to create state and render
to display HTML elements, how to create event handlers to handle event listeners, and how to refer to and use state values using this.state.something
and how to set state using setState()
.
And if I wanted to create a class component that would display a fully functional text input where text could be typed in and the input data could be saved somewhere for later use, there are a few things I'd have to take into consideration first. I would need to:
- create state in my constructor,
- render the input tag and assign its value to its state value, and
- add event handlers that would take in data as its being changed, then re-set or update the value of state on every change.
And the React code would look like this:
import React, { Component } from "react";
export default class StandardReactForm extends Component {
// Create state using constructor boilerplate
constructor() {
super();
this.state = {
name: "Peanut"
}
}
// Create event handlers to accept input values and update state
handleNameChange = (ev) => {
this.setState({
name: ev.target.value
})
}
//render input tag
render() {
return (
<div>
<form>
<label>Name:
<input
type="text"
name="name"
// set current value of input to current state value
value={this.state.name}
// refer to event handler on input change
onChange={this.handleNameChange}
/>
</label>
</form>
</div>
);
}
};
Functional Components and Why I Never Loved Them
Just as I was getting a handle on class components, my instructors introduced and occasionally encouraged using functional components, which are structured quite differently in a few ways. And for several reasons, it was hard for me to warm up to them.
Although functional took props as an argument (which was convenient...I guess...), it was something extra to remember. In a class component you referred to props using this.props.data
while in a functional component, you'd just refer to it as just props.data
. If functional components saved me time or effort in having to type an extra this
, I also wasted time mistyping my references to props as I worked between using class and functional components.
Also, unlike in a class component where you could define methods, you had to declare functions using const
in a functional component. Again, this made me prone to making more mistakes as it was one more thing that I needed to remember...if I could even remember I was coding inside a functional component.
Finally, in a functional component, you couldn't create or set state or use lifecycle methods. I didn't think that would make a huge difference in the way that I already structured components because if I didn't need to create state or update it, I would simply choose to omit the constructor in my class component.
There just didn't seem to be enough gain in using both functional and class components when I could just always and reliably use class components. I appreciated consistency, and instead of switching back and forth and constantly making mistakes, I preferred to stick with a single type if it could be helped.
With a Single Hook, Class Components are Knocked Out of the Ring... And Functional Components Win!
When it finally came time to investigate and better understand hooks, I found that they weren't as complicated as I expected them to be. Like all feature updates, they're made to make your life easier and simpler!
useState
, for example, is a wonderfully clean way to set up local state. In just a single line, you can declare a variable name for the state you want to keep track of, a function that would set state inside of an event handler, and initialize the state value, all inside of a functional component!
Take a look for yourself! That hook looks slick!
import React, { useState } from "react";
// functional component
const HooksForm = props => {
// create state property 'name' and initialize it
const [name, setName] = useState("Peanut");
const handleNameChange = e => setName(e.target.value);
return (
<div>
<form>
<label>Name:
<input
type="text"
name="name"
// set current value of input to current state value
value={name}
// refer to event handler on input change
onChange={handleNameChange}
/>
</label>
</form>
</div>
);
};
export default HooksForm;
There are so many upsides to using useState()
here.
- We can avoid using
constructor
to create state. - We can knock out two tasks in one shot. Here we defined a variable, "name" with an initial state value "Peanut", as well as a specific function "setName" whose only function is to update it.
- This saves us from having to write so many lines of code. It's succinct and it looks way cleaner and easier to read.
- We can just refer to the state property or its set-function by its name, and just its name, wherever we need it. No more chaining
this
orthis.state
.
Most of all, (and this is my favorite part about this method) we never again have to be tortured by whether we should use a class or functional component. I'm very happy knowing I can choose just one, stick with it, and feel confident that it will do what I want it to.
*For more information about hooks, please read the excellent documentation over at React Docs
Top comments (4)
Does that mean you now choose functional components first? What is your thought process as you begin? With hooks I do know many if not all require functional components which was very restrictive in the past. I’m thinking of making the transition next time I have to create a new component. Thanks!
Yes, now I'll typically opt to use functional components first. Having gained more experience since I wrote this blog, I'm finding that functional components are not as limiting as I also used to believe, and that I can, in fact, perform a lot of common lifecycle methods using hooks, so there's no real incentive for me to go back to using class components. I will say that I don't feel completely comfortable using a particular hook and I'm in a real pinch, I might consider using a class component. But like I mention in this blog, I like to stay consistent, so I'll continue working on my hooks skills so that I can just use functional components every time.
And one more note about why I use functional components:
I'm discovering that there are a lot of React-based packages that I may want to use, such as React-Bootstrap, and if I want to be able to apply those packages to my app component, it's better that I get used to writing functional components.
Good luck with your transition! Hope it's a happy one!
I do like function components either, hooks arrived just in time, when i switched to a React! And imo, classes fit better on a server side, e.g.: when you creating a model with class it's more convenient.