Plenty of blog posts that focus on the fundamentals of implementing Hooks have already been written, so rather than add another one to the pile, I thought it might be a good idea to expand into some less-explored space.
The first part of this post touches on the motivation for using Hooks in the first place. Following code-alongs is a great way to learn, but sometimes tutorials skimp when it comes to providing reasoning for doing things in a certain way, which, as a skeptical person, always makes me feel a little uneasy.
So, I wrote the same component twice, once as a class, then as a function, and compared and contrasted them.
The second part is a tutorial on writing custom hooks to extract repetitious logic.
I hope you find the content useful!
Let's begin!
Why use hooks?
In a sentence, hooks save time and are clean.
Here's how:
They reduce boilerplate
Compare the two components above which render identical DOM elements. Note how Function components require no constructor or render functions, and no this
* keyword (written 7 times in the Class component!) is required to bind toggleMode()
or when calling methods to change state
.
Unsure about this
? Tyler McGinnis breaks it down very well here.
They reduce decision-making overhead
Using only Function components reduces decision-making overhead simply because we never have to make a choice between Class and Function.
- Should this be a Function or Class component?
- Would refactoring this to a Class be a pain if I need to add state?
- Am I positive that it will always/never need state?
Prior to the release of the useState
Hook, we had no choice but to use Classes for statefulness, but all of the questions above become moot once you've embraced the Function-Hook paradigm.
They reduce refactoring
One of the more common implementation details that changes through the development cycle of React applications is the addition of state to a component. With Function-Hooks, you can immediately add state and skip the preliminary step of rewriting to Class.
Reusing useState
in a custom Hook
The second part of this post is a short tutorial on writing a custom hook. If you would like to follow along (suggested!), code is available here, including starter code and solutions.
Another BIG advantage of Hooks is that they are re-usable, which helps us keep solutions nice and DRY, another way to save time and keep code clean.
Example
Adding items to a shopping cart is a common usecase for state in ecommerce applications.
Take a moment to review code for the FruitStand
component below, and we'll resume underneath when you're done.
If the repeated increment logic smells a little off 💩, that's a good sign! This is the redundant code that we will extract into a single custom Hook, useIncrement
.
A couple of details to note:
- Because there is no JSX, there is no need to import React.
- State and the function that changes it,
increment()
, are returned by the hook in an array and accessed by destructuring in the familiar[foo, setFoo] = useHook(<initial value>)
pattern
Reformatting FruitStand
Reformatting the component is very straightforward.
- Import
useIncrement
- Remove the
useState
import - Implement
useIncrement
for both fruit types at the top of the component. - delete the redundant
incrementApples
andincrementOranges
functions - re-assign add button
onClick
to the state-setting functions ofuseIncrement
for apples and oranges.
Challenge!
Implement a decrement function for apples and oranges, using a Hook called useDecrement
. No negative values allowed 😀
Conclusion
This single component example is very simple, so the benefits of useIncrement
might not be obvious, but I'm sure you can imagine a situation in the real world where extracting repeated logic would be beneficial.
I hope I've made a strong case that Function components with useState
have the potential to decrease development time in multiple ways, and provide a much cleaner and readable way to write stateful components.
Top comments (0)