The slightly misleading terminology of react hooks
Jack
Posted on February 5, 2021
So react hooks are awesome, they make components much simpler, they let you abstract your component logic and completely do away with class components.
However; the names of these hooks are somewhat misleading. Especially after react went all functional on us with function components.
Allow me to elaborate:
Side Effects
What is a side effect? A side effect is when a function changes another part of an application outside of its own scope:
function goHome() {
window.location.href = '/home';
}
Calling this function is updating the window location, which is a global variable and isn't part of its own scope, so it's a side effect.
It's also worth quickly also covering side effect's partner-in-crime:
Idempotent
An idempotent function will return the same value for the same set of inputs every time.
function getPath() {
return window.location.pathname;
}
This function is not idempotent. If the location were to change, you would get a different result.
With that out of the way, let's talk about useEffect
:
useEffect
Accepts a function that contains imperative, possibly effectful code.
useEffect(() => {
window.location.href = '/home';
}, []);
The useEffect hook allows you to do effectful behaviour inside a functional component.
If you do a side effect inside useEffect, react pushes that side effect to the end of the render cycle. In react terms, useEffect is about protecting the render cycle, not about removing side effects.
Why is this distinction important? We often talk about react components as being "pure". A pure component should be side-effect-free and idempotent. Wrapping your side effects in useEffect does not mean your component is still pure.
useState
I've seen many people say things like "we don't need smart/dumb components now we have hooks"
I don't want to go in-depth into patterns and architecture, but just because you're using useState instead of redux, etc, you're still introducing state into a component. This breaks a component's idempotency.
For every piece of state a component manages, the harder it is to reason about, test, and control that component.
Tl;dr useState is no different to any other component state - it is not functional.
Function vs Functional component
Okay something that I only really noticed recently: we always talk about functional
components but actually, the docs refer to these as function
components. What's the difference?
I believe the difference is this:
A functional
component adheres to the rules of Functional Programming. It is idempotent, pure, and stateless.
A function
component is just any old component that just happens to be a function.
That's a pretty big discrepancy. When we're talking about function components, do we care about whether it's a functional component?
I used to believe that yes; any function component should be side-effect and state free. Now I'm not so sure.
Conclusion
We've definitely got some confusing terminology here. useEffect
is not offering some way of keeping effects "out" of your component. And a function
component is not the same as a functional
component.
Should I stop using hooks?
Absolutely not. Hooks are awesome. I just want us to be mindful that hooks are not some magical construct that preserves function purity. If your component has state or causes side effects, useState
and useEffect
do not change this fact.
Posted on February 5, 2021
Join Our Newsletter. No Spam, Only the good stuff.
Sign up to receive the latest update from our blog.
Related
February 20, 2023