About Me: I've been a professional web developer for just over 10 years now. I'm currently the lead web development instructor at Better Coding Academy, and as part of what I do, I post videos on our YouTube channel at https://www.youtube.com/c/BetterCodingAcademy.
(Subscribe for awesome web development content!)
The following content was sourced from the Better Coding Academy style guide.
When deciding between hooks, render props and higher-order components, always go with hooks wherever possible.
// #1 - best
const MyComponent = () => {
const mousePosition = useMouse();
// mousePosition.x, mousePosition.y
}
// #2 - not as good
const MyComponent = () => {
return (
<Mouse>
{({ x, y }) => {
// ...
}}
</Mouse>
)
}
// #3 - bad
const MyComponent = ({ x, y }) => {
// ...
}
export default withMouse(MyComponent);
Why? Well, let's start with higher-order components (HOCs).
Why are higher-order components bad?
Higher order components are bad for two main reasons:
-
They take up a fixed prop name, possibly removing other props. For example, imagine for above example #3 we want to include an
x
andy
prop on the component:
<MyComponent x="some value" y="some other value" />
Both of these values will be overwritten by the values coming from the higher order component. This issue can also arise when you wish to use multiple higher order components:
export default withMouse(withPage(MyComponent)); // if withMouse and withPage set the same props, there will be clashing issues
They do not clearly identify the source of your data.
withMouse(MyComponent)
does not tell you which props are being included onto the component (if any), hence increasing the amount of time spent debugging and fixing up the code.
Okay then, now let's look at render props. Because render props give you data within a function parameter, you can freely rename it however you like. For example:
<Mouse>
{({ x, y }) => (
<Page>
{({ x: pageX, y: pageY }) => {
// ^ big brain
}}
</Page>
)}
</Mouse>
Okay, well what about render props?
However, render props still have their own issues:
-
They don't allow you to use their data outside of the
return
statement. With the example above, you can't use thex
andy
values in any state variables,useEffect
hooks, or any other functions within your component, because it's only accessible within thereturn
statement. -
They get nested... really quickly. Imagine we have three render prop components within a given component:
const MyComponent = () => { return ( <Mouse> {({ x, y }) => ( <Page> {({ x: pageX, y: pageY }) => ( <Connection> {({ api }) => { // yikes }} </Connection> )} </Page> )} </Mouse> ) };
So now, onto the final (and best) solution!
How hooks solve all of these issues!
Hooks address all of the above issues.
-
Hooks don't have any fixed prop names - you can rename however you like:
const { x, y } = useMouse(); const { x: pageX, y: pageY } = usePage();
Hooks clearly identify the source of the data - in the example above, it's clear that
x
andy
come fromuseMouse
, andpageX
andpageY
come fromusePage
.-
Hooks allow you to access data outside of the
return
statement. For example, you can do stuff like:
const { x: pageX, y: pageY } = usePage(); useEffect(() => { // this runs whenever pageX or pageY changes }, [pageX, pageY]);
-
Hooks don't get nested at all. With the above render prop monstrosity rewritten using hooks, the code would look something like:
const { x, y } = useMouse(); const { x: pageX, y: pageY } = usePage(); const { api } = useConnection();
Three lines of beautiful code.
Hope you guys enjoyed this comparison between three architectural patterns within React! Be sure to follow me on YouTube for tons of free, full-length React, JavaScript, Node.js and general web development tutorials.
Happy coding!
Top comments (14)
Hi, π May I know which software you used to record the videos. is it freeware. And did you used normal mobile headphones as mic ?
I use OBS to record the videos with an AT2020 mic :)
Actually I thought you are using some paid ones like
Camtasia
, But Good to hear that by using OBS your videos are clear. Have you configured some special settings in OBS ?Nope - OBS is really good. Since it's screen recording there really isn't too much variation in quality; it's more important to have a good microphone setup (something I definitely can improve upon π)
Other problems with HoC are,
It does not clearly identify the source of your data - you have no idea where
x
andy
come from :)They don't need to know, just like with Dependency Injection in Angular.
Drawing a similarity between Angular and React here isn't particularly beneficial.
In React, tracking down where a particular prop comes from within a nest of multiple HOCs is a huge pain and a massive code smell that Hooks has since addressed beautifully.
Aren't we talking about the dependencies of a component?
I don't know why it is necessary to know the source of a dependency inside a component.
this is very useful, thank you
You're welcome Nico!
youtube.com/watch?v=xiKMbmDv-Vw&fe...
However I choose Hooks, if I'm able to, I don't think your arguments on higher-order components are strong, as they had to be, anyway thanks.
Even though the codebase I'm working on right now is mostly with hooks, there are a couple of HOCs and render props thrown in. I think each of them have their appropriate use.