Photo by Dave Phillips on Unsplash
Kent C. Dodds has a great post, 5 Tips to Help You Avoid React Hooks Pitfalls. There's lots of great advice in there, but I'm curious what issues all you wonderful devs on DEV have encountered in regards to React Hooks.
It could be a production application or a side project you're working on. It could be a small issue you encountered or it could be a whale of an issue you struggled with.
It could be an issue that stumped you with an out of the box hook, a 3rd party hook or your own custom hook.
Go!
Top comments (14)
Most of my work has been converting older class-based components to functional components, which means also using hooks. I think the syntax around passing
useEffect
which components to watch is a little weird. The distinction between[], empty, [prop]
is harder to grasp than the class methods. AlsouseRef
is a little tricky because I need to use thecurrent
property which took a little digging through the docs to realize. Overall I think they are a good way to keep functional components small and isolated.For the most part I think hooks are a game changer, but there's one area I wish could be improved - using Redux's
useDispatch
insideuseEffect
. ESLint (or better yet, the rules of hooks) enforce you to pass the dispatch object as a dependency, resulting in an effect that fires on every render.mapDispatchToProps
to the rescue!Does it work to get the dispatch method with usedispatch outside (possibly with a usecallback) and then you can pass dispatch in to the useEffect and that shouldn't then change every render. I think that's how you are meant to manage it
I guess it should work, but if you're going through so much trouble,
mapDispatchToProps
will probably be easierI have a strong preference towards ditching the container/component split as it's hard for new react Devs to pick up and navigate the code. I'm not sure that passing in an extra prop is too much effort, but it is subjective
Totally agree. Encountered the same issue too and it's annoying to manually disable the linter for this line.
We were lucky to start a green field project with React around the Hooks beta, going live as it went to production. For me it's the reason we are using React now, it's so much cleaner and less complexity with hooks. We have found some interesting issues with async (just wrote an article on that) which we've found very elegant ways around, thanks again to hooks.
The biggest complexities for us have been the reduction of renders and understanding why they are happening. Plus a few cases of our model breaking the rules and calling
update
functions after some async when the component has become unmounted in the interim.We've cleaned a lot of this up by doing a few wrapped hooks of our own that ensure nothing accidentally goes astray - keeps the code neater too.
I've been through several variations of fetching with useEffect, and I finally settled in on something without dependency arrays. The previous version lacked clarity when trying to fetch two or three things in a specific order, and performing state checks in the effect(s), e.g.,
if (!states), if (states && !zips)
or something. Please excuse all of my contrived examples:Of course, there are already three pieces of state moving in the same direction, and even with an object things will get pretty unruly, so it made sense to throw the state into a context to handle all the different endpoints:
This worked fine, too. Even if I included dispatch and status in the dependency array, it was no problem. Unfortunately, there's no cleanup, and that should not go missing:
Suddenly, I have an issue where as soon as the status is changed to loading, the fetch is cancelled. I added a check for the additional status,
status === 'idle' || status === 'loading'
, and while my dog arrived unharmed, it wasn't without a cancelled request happening first. I need to get back to the code sandbox I was tinkering with when I was learning this bit.The other time I run into issues with useEffect is when I am watching a dependency for a change, and the subsequent update causes a change to the dependency. I've stopped a runaway like this before by freezing the initial dependency with useRef, something along the lines of:
For the most part I think hooks are great, and often make code reusability very simple, without the need to manually reimplement things into classes, or make tons of wrapper components.
The issue I have generally isn't with hooks itself, but the docs. They could often do with better and more in-depth explanations as to how they work. Some examples:
It's not specifically documentation but if you want answers to all these questions, follow Dan abramov on Twitter and on his amazing blog overreacted.io. that really helped me understand at a deep level
This post is a must-read IMHO, overreacted.io/a-complete-guide-to...
How can I replicate the behavior of
componentWillUnmount
? It's important when the component subscribes to events when mounted.Does returning a callback function for cleanup not work in your case?
Missed that feature, thanks for letting me know.