Two (More) Ways to Get Hooked on React
Making cleaner code and simpler components helps keep errors from hiding, and increases the reusability of each component. Hooks were announced in 2018's React conference, and have been an absolute game changer for React development! Not only can we start shedding class lifecycle methods and make more functional components, Hooks help make our code more compact, readable, and reusable.
Simplify existing components
Take one of the simpler examples, a button that keeps a state of how many times we click it. In React 16.7, we might write something like this:
We created two components:
- ClickTrackerButton, Our presentation component. The button will display how many times it has been pressed, and when the button is pressed, it will send a signal to the
onPress
prop that was passed to it. - ButtonInstance, Our Container component, the source of state for the component, and a way to update state.
In this example, we broke apart the display and state management to illustrate a design pattern I strongly recommend, the Presentation / Container pattern. This will help improve the reuse and testability of the components. Rendering a ButtonInstance
looks fairly straightforward, as-is, in React 16.7, but what if we migrate it to use Hooks (React >= 16.8)?
function ButtonInstance(): ReactElement {
const [pressedCounter, setCounter] = React.useState<number>(0);
const onPress = () => setCounter(prevCounter => prevCounter + 1);
return <ClickTrackerButton pressed={pressedCounter} onPress={onPress} />;
}
It uses the useState() hook, setting the initial value to zero, and creates two variables, a pressedCounter
to store the current state and a setCounter
method to update the state of pressedCounter
. Because we are incrementing the previous value, we still need to use a lambda to reference the old value and never use pressedCounter
directly in the setting method.
What are the major differences?
- There's significantly less code for bugs to hide.
- We don't need a class for
ButtonInstance
, so much of the syntactic sugar around the constructor and lifecycle methods that aren't part of the business logic can be removed. - We can encapsulate the entire container in 3 lines of clean typescript.
- We no longer need a state interface and can still keep the button clicks strongly typed.
UseEffect hook
Taking our initial ButtonInstance, and adding a DOM manipulation, we would add two lifecycle methods, some handling code, and end up with this being added to the class:
componentDidMount() {
this.titleUpdate();
}
componentDidUpdate() {
this.titleUpdate();
}
const titleUpdate = () => {
document.title = `Button was pressed ${this.state.pressedCounter} times`;
}
We added the ComponentDidMount and ComponentDidUpdate lifecycle methods to the class, as well as the handling code. Doing this with Hooks is just one small add to the existing code adjusting the document title:
React.useEffect(() => {
document.title = `Button was pressed ${pressedCounter} times`;
});
Where to go from here
This is just two of the ways we can successfully leverage Hooks to clean up our components, and help make better React code. Check out the Official Documentation and start using Hooks today!