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!
In a sentence, hooks save time and are clean.
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
this? Tyler McGinnis breaks it down very well here.
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.
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.
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.
Adding items to a shopping cart is a common usecase for state in ecommerce applications.
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,
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 the component is very straightforward.
- Remove the
useIncrementfor both fruit types at the top of the component.
- delete the redundant
- re-assign add button
onClickto the state-setting functions of
useIncrementfor apples and oranges.
Implement a decrement function for apples and oranges, using a Hook called
useDecrement. No negative values allowed 😀
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.