
Frustrations with React Hooks - efunction
https://blog.logrocket.com/frustrations-with-react-hooks/
======
bestest
I absolutely love hooks and don't want to use the `React.Component` class ever
again.

And yes, hooks need to be grasped, they're quite something else. But once you
get the hang of hooks, they're very simple to understand.

OP seems to be a bit stuck in a hole.

If you end up in a situation where your hooks come loose and the code becomes
a mess — just delete them all and rethink your code / component logic
structure. Believe me, it all can be simplified. Just rinse and repeat until
you are satisfied with the outcome. That's when the "aha!" moment comes.

At the moment I only use `useEffect`, `useState`, `useRef` — the rest is
unneeded so far even in my large-ish application.

P.S. sorry for the puns!

~~~
marmada
I don't understand the hate against class based components. React class-based
components are dead simple to understand.

~~~
s_y_n_t_a_x
Nothing is simpler than a function. Easier to write, debug, and test.

* Removed "pure" to make my main point clear.

~~~
istoica
How are your functions pure if inside them you call `useEffect`, `useState` ?
Where is pureness when at first look they generate side effects, or am I
missing something ?

~~~
s_y_n_t_a_x
Not all functions needs hooks, not all hooks break pureness.

But my point was functions are simpler in all those scenarios, pure or not.
Edited my comment to reflect that.

~~~
csande17
> not all hooks break pureness

Sure, if you define a function called useWhatever that doesn't actually call
any hooks, that might be a pure function. But the restrictions described in
[https://reactjs.org/docs/hooks-rules.html](https://reactjs.org/docs/hooks-
rules.html) are not restrictions that pure functions have.

------
halfmatthalfcat
I was extremely skeptical of hooks in the beginning after having used class-
based lifecycle components for a long time. Overall, I _think_ it's been a net
positive but I end up feeling that I'm writing more code at the expense of
using well defined constructs (lifecycle methods).

I usually feel like I'm writing too many effects which update state(s) and the
lifecycle flow becomes harder to contain mentally, however there are times
where I'm like "this is definitely easier or less of a cluster then it use to
be".

So I think the jury is still out. In terms of Hook's initial premise of "we're
doing this so that developers unfamiliar with class-based OO paradigms can
work better/faster", I don't think it added any more clarity or ease-of-use
over the class based lifecycle methods tbh.

~~~
pkilgore
Maybe this is because I'm a "developer[] unfamiliar with class-based OO
paradigms" but I find hooks components easier to read later. You start at the
top, read to the bottom, and assuming you can catch crazy indirection within a
hook callback during review, that's what happened. No HOCs. No having to
memorize an externally documented lifecycle order. No having to cross-
reference methods against the state they update 50-60 lines up the file.

I'm genuinely curious if the difference is because I was doing tons of
Recompose/HOC style components before hooks came out.

Also, just FYI, it didn't click for me until this tweet[1]:

> The question is not "when does this effect run" the question is "with which
> state does this effect synchronize with"

> useEffect(fn) // all state

> useEffect(fn, []) // no state

> useEffect(fn, [these, states])

[1]
[https://mobile.twitter.com/ryanflorence/status/1125041041063...](https://mobile.twitter.com/ryanflorence/status/1125041041063665666)

------
YuukiRey
Many people aren't event aware of the unnecessary renders caused by using
hooks. If your app is so tiny that it doesn't matter if everything renders all
the time, then you might not be aware of your `useCallback` recreating
callbacks way too often
([https://github.com/facebook/react/issues/14099](https://github.com/facebook/react/issues/14099)),
or that you're not even using it in the first place. Considering that front
end is probably the area of software development that attracts the largest
share of people like me - self taught, no computer science background - I'd
also assume that many people love the perceived simplicity of hooks without
realizing that it makes their code worse.

It'll only become apparent when you app is large and complex enough that it
suddenly starts to matter when things re-render and then you'll be faced with
tracking down those re-renders and fixing dependency arrays everywhere.

With classes, the naive solution is the right one when it comes to preserving
function identities across renders.

Not saying hooks are bad, but they're not all roses and sushine.

~~~
acemarke
A lot of people don't understand that React's default behavior is to re-render
_everything_.

When a component is rendered, React will recursively re-render all descendants
of that component. Out of the box, React doesn't do any optimizations like
"skip rendering this component if the props haven't changed". Because of that,
"re-creating callbacks" isn't an issue in base behavior [0], because there's
nothing that cares if it's a new function reference or not.

It's only when child components are attempting to optimize perf by comparing
props and avoiding re-renders that having consistent callback function
references matters (ie, `React.memo()`, `PureComponent`, and React-Redux's
`connect()`).

[0] [https://reactjs.org/docs/hooks-faq.html#are-hooks-slow-
becau...](https://reactjs.org/docs/hooks-faq.html#are-hooks-slow-because-of-
creating-functions-in-render)

~~~
csande17
Yeah, React seems to have been designed under the assumption that DOM
operations are the only thing front-end code can do that takes non-zero time.
Like, here's the first line of their document describing how to use to improve
performance using things like PureComponent:
([https://reactjs.org/docs/optimizing-
performance.html](https://reactjs.org/docs/optimizing-performance.html))

> Internally, React uses several clever techniques to minimize the number of
> costly DOM operations required to update the UI. For many applications,
> using React will lead to a fast user interface without doing much work to
> specifically optimize for performance.

My experience with React applications (both writing them and as an end-user)
hasn't really borne this out.

~~~
ng12
Could you elaborate? Rendering perf is pretty much the least of my concerns,
even on my apps which support IE10. Most "perf" problems I find are related to
fetching and appropriately caching data.

~~~
stickfigure
Not the parent, but here's one that I hit recently:

I hoisted the state of an input box up a few layers because other parts of my
app are affected by the current typed content. Since I'd been careless passing
closures in as props to expensive components, they were getting re-rendered on
every keystroke. It was noticeably sluggish.

~~~
acemarke
Just out of curiosity, is that in production mode, or just in development?

~~~
stickfigure
It affected production enough to get some user complaints.

------
eternalny1
> This is yet another JavaScript paradigm to learn. For the record, I am a
> 49-year-old React fanboy. I am a freelancer and use other frameworks apart
> from React, and this gives me fatigue.

Amen to that. The fact that still are in "here's a 'better' idea, let's try
this" landscape in JavaScript is depressing.

I no longer jump on these new frameworks when the bandwagon flies by. I ignore
postings for jobs saying they are rewriting their system in "new Framework
Y!". I don't care how "pure" your new design is, I care about having it work
well in the trenches.

I, too, am tired.

And old.

~~~
enobrev
React Hooks and Containerizing Everything are the things this old "Webmaster"
is kicking down the road until all the bugs are shaken out. I also skipped
gulp and grunt and jumped straight into webpack, which I've read far too much
about to understand so little.

------
bcheung
Overall I think React hooks are an improvement. My codebase is usually shorter
and there is a lot less typing involved.

But hooks creates abstractions the developer needs to deal with that never
existed before.

Hooks are not functional because they break referential transparency of
functions.

You have to track dependencies manually and hooks are more difficult than they
need to be for the "componentDidMount" equivalent. If you don't get the
dependencies just right you end up with things not firing or in infinite
loops.

You have to wrap your functions in "useCallback" or "useRef" just so the
reference doesn't change and cause infinite loops.

You can't create abstractions where a hook calls another hook. So you end up
having to inline a bunch more code into your function rather than outsourcing
it into a helper function.

The positional order seems like it would be easy to work around if they
allowed you to pass in a key. Not sure why that isn't available.

~~~
shantly
> The positional order seems like it would be easy to work around if they
> allowed you to pass in a key. Not sure why that isn't available.

IIRC it's because they implemented their own method lookup table (!) to
associate with the Component object (!) but as a FIFO queue, more or less. I
assume either for ideological (that's how they wanted it to work) reasons or
because they (probably correctly) reasoned that loading down React apps with
more strings at such a basic level would risk performance/memory problems.
Plus if they did that then it'd _really_ look like a method lookup table and
be more obviously Rube-Goldbergian than it already is.

~~~
bcheung
They can make the string part optional. Variables and symbol tables have been
staples of programming languages and compilers for ages now. It's a very
standard pattern. Nothing Rube-Goldberg about it.

But React has deviated so far from both the OOP, FP, and traditional
programming paradigms that now it kind of feels like hacks are needed to
compensate for hacks.

~~~
shantly
I mean at the point you're writing a symbol table and associating it with an
object so you can figure out which method to call in its context, probably it
occurs to you that you're _entirely_ re-creating a feature the language
already has (but slower and worse) rather than just _mostly_ doing so, as they
are now.

------
tjchear
I never understood the need for hooks and how it's used (the example that
react doc has for useState is too simplistic for any useful pedagogical
reasons) until I saw divjoy's generated code and studied how it used hooks.
Then everything clicked and I've been more productive using hooks than I ever
had with react classes. I can attest that cognitive load is lower with hooks
than with classes.

------
bcyn
I don't agree with the author's statement that there are only two (very
involved) solutions to the pagination problem (re: section titled "React
relies on the order in which Hooks are called").

It can easily be solved by just setting the state in the event handler, since
the state is included in the dependencies array for the fetch effect:

[https://codesandbox.io/s/dependency-
array-0u3sc](https://codesandbox.io/s/dependency-array-0u3sc)

The answer to this question posed by the author?

> On line 23, the useFetch Hook will be called once on the first render. On
> lines 35 – 38, pagination buttons are rendered but how would we call the
> useFetch Hook from the event handlers of these buttons?

We can call `useFetch` again by triggering a re-render. This hasn't changed at
all with the introduction of hooks: new props or new state still triggers a
re-render.

~~~
tylerFowler
I wondered about this too, in general I think the article misses that updating
state is the key to "causing" effects. Rather than latching onto the callback
model to explicitly "run" effects.

Though I'll admit getting the relationship of state and effects caused by
changes to that state can be more difficult to work out mentally, I think it
results in a more complete understanding of what a component actually does.

~~~
bcyn
I agree it's not intuitive at first. As someone pointed out on Twitter (can't
find link at the moment):

A good mental model is that the second argument to useEffect defines which
pieces of state that effect syncs with.

useEffect(() => {}, undefined) // Sync with all state

useEffect(() => {}, []) // Sync with no state

useEffect(() => {}, [a, b]) // Sync with `a` & `b`

~~~
acemarke
Original source was Ryan Florence:

[https://twitter.com/ryanflorence/status/1125041041063665666](https://twitter.com/ryanflorence/status/1125041041063665666)

------
Blackstone4
I spent maybe 1.5-2 years working on a medium size React app and after taking
maybe 6 months off, I came back to it. I started reading about React Hooks and
honestly I did not fully understand them. Maybe it's just JS fatigue and me
feeling like I'm trying to building a house on quick sand. Everything is
always changing...

Recently I built a bolierplate JSON-api web app project in vuejs and golang
(previously I was using TypeScript, Apollo GraphQL and Express). I find the
terminology around vuejs much more user friendly and it comes with a router
and state management built in...I try to avoid using any other JS module. The
golang ecosystem is much more stable than nodejs which is a relief....I have a
feeling I might just settle on vuejs + golang for all future web apps

------
iraldir
Interesting to hear someone who clearly tried to use it seriously. That said I
do agree with the first comment on the article itself, he is using his
"useFetch" in a very far fetched (haha) way. A hooks should not be called as a
callback to an event, you should "trigger an action" (whether redux, a
callback from a higher component etc.) that update a state which in turns
trigger the hook. I understand this can be length / annoyingly administrative
but that is the cost of the react architecture, with the payoff being to
better understand the flow of the application.

~~~
concerned_user
I use redux and react-saga for more complex flows, sagas translate into
generators and make async code flows look almost like synchronous code which
is nice.

~~~
machiaweliczny
Sagas are nice to read but hard to test. IMO simpler async functions are
enough. Is there any benefit to sagas that I don't see?

~~~
acemarke
Sagas are a great power tool... and 95% of Redux apps don't actually need
them. Using them just for basic data fetching is overkill. Sagas are most
useful when you need to do complex async logic, like cancellation, debouncing,
and decoupled "background-thread"-like computations.

Thunks are sufficient for most use cases, but the main thing they can't do is
respond to dispatched actions.

For more info, see the Redux FAQ entry on choosing an async middleware:

[https://redux.js.org/faq/actions#what-async-middleware-
shoul...](https://redux.js.org/faq/actions#what-async-middleware-should-i-use-
how-do-you-decide-between-thunks-sagas-observables-or-something-else)

------
hardwaregeek
useEffect is such a weird name. I get that it's kinda general in usecases but
whenever I see the name my first thought is "what the hell is an effect and
when do I use them?" and this is coming from someone who has actually heard
about effect systems. Going from componentDidMount which is a nice, clear name
that dictates when the function is run, to useEffect(() =>
console.log("Mounting!"), []) is so confusing. I'm not super thrilled that the
difference between running on mount, on new props and on unmount is implicitly
determined via the second argument or returning a new function. I get that
useEffect has a nice coherence and is more general but that's not always a
good thing.

Not to mention the docs for useEffect just mention the one usecase of running
on mount and on update and neglect to even talk about running something just
on mount.

That being said, the reducer hook is amazing and a great replacement for
overly complicated setState or overly simple Redux stores. Definitely reminds
me of ReasonReact in a good way.

------
nooyurrsdey
What's lost in all this is that classes are simple and understandable.
Introducing all these new paradigms removes that simplicity. Everyone is ready
to hate on classes but they have been robust structures for a long time

~~~
Unbeliever69
I think that what is lost is that Javascript is more of a functional language
than an object-oriented one and a move to hooks embraces its functional roots
while eliminating numerous footguns (this), simplifying reuse, and reducing
redundancy.

~~~
filleduchaos
I don't quite see how Javascript pre-ES5 was any more of a functional language
than, say, Ruby at the time (a notoriously OO language).

"It uses prototypes, not classes!" simply makes it a different kind of object-
oriented.

------
kevsim
We’ve writing most new code with hooks (including the Apollo GraphQL hooks
like useQuery and useMutation). Generally been really pleased with them but
did get bitten hard the other day.

The value returned from useState is just a plain ol’ variable like any other
so it also gets captured by closures like any another variable. We had an
editor that updated some state and then an event handler (defined as a
closure) that did something with the state variable. The state was updated as
expected but when the event fired, the closure had the original value. It can
be worked around via a container/useRef (and is maybe a code smell in the
first place) but it made for some painful debugging.

------
flabbergast
I'm done with React. They keep re-inventing the wheel, and every iteration is
full of issues that need to get resolved with yet another design principle.

~~~
RussianCow
I'm also frustrated with the introduction of a completely new paradigm, but to
be fair to the React team, hooks are really innovative and don't re-invent the
wheel at all. I, for one, have never used another framework that had anything
similar to hooks.

------
latte
Coming from a ClojureScript / Reagent background, functional components and
hooks look very natural, useState being largely equivalent to
reagent.core/atom. useEffect and useRef look like a logical extension of the
same idea.

------
mattkrick
Hooks are absolutely fantastic. However, there are still a few pain points:

\- useState with an array is bad news if more than 1 component is consuming or
setting the state.The clunky alternative is to keep it in a ref & call a
forceUpdate whenever you would normally call your setter

\- useCallback doesn't scratch the itch for things like document event
listeners since everything inside the callback will be stale. The clunky
alternative is a custom useEventCallback that keeps your callback function in
a ref. (and that might not work in the upcoming sync mode)

\- linter rules can be too strict & the --fix flag can actually cause a break
in your app by adding things to the dependency list. Sometimes a useEffect
depends on the current value of a ref, but linter says that's a no-no. 2
useCallbacks can be co-dependent, but there's no way to write that co-
dependence in the dependency list. Sometimes I want to return null before a
hook. The clunky alternative for all these is a bunch of eslint-ignore
comments.

~~~
dceddia
> useState with an array with more than 1 component setting the state...

It sounds like you might be setting state by modifying the array and then
calling the setter. This won't work:

    
    
        array.push(thing)
        setArray(array)
    

Instead, you have to update the array immutably, like setArray([...array,
thing]).

> useCallback for event listeners

useEffect is usually the right place to set up event listeners (and has a
built-in way of cleaning them up, by returning a cleanup function).

> Sometimes I want to return null before a hook.

Hooks pretty much have to be at the very top of the component, and eslint-
ignore'ing those errors will probably cause weird issues later. Better to
think about another way to solve the problem that doesn't involve returning
early.

An issue I ran into recently: I had a modal Edit dialog with some form state
that was initialized with the current values of the thing I wanted to edit. If
that modal was always mounted and merely shown/hidden (<Modal
isOpen={itemToEdit}/>), the state would be initialized _once_ and wouldn't
update when I changed the item-to-be-edited. The fix was to unmount the
dialog, and only mount it when there was an item to edit, {itemToEdit &&
<Modal isOpen={true}/>}

------
k__
The dependency array is the single most important improvement that hooks bring
over lifecycle methods.

You're component gets rerendered when the array changes and not when you got
the right mix of lifecycle methods going.

But yes, it's not always obvious what changes you really care for.

~~~
matsemann
It actually reminds me of $scope.$watch from Angular 1.

------
littlecranky67
One major point of the author is complaining that the dependency array in an
effect is only compared by reference for objects and arrays.

To me this is a feature rather than a shortcomming: I use immutable data
structures all the time (with array and object spread operators it is really
easy to do so) and the effect will only update when it really needs to - thus
only triggering a re-render (or rather reconciliation) when something has
actually changed. This is in contrast to .setState() which triggered
reconciliation regardless if a value actually changed.

~~~
latortuga
The example in the article can be fixed very easily and doesn't require
immutable data structures. If you're fetching something from a url and you
don't want to fetch twice from the same url, make the dependency the url
itself.

~~~
PKop
More generally, one should be destructuring object properties (since he later
did that anyways) at the top of the function. It's no more typing, but
isolates property usage to one spot. Then pass them into the dependency array.

Seems very convoluted to do that inside the useEffect, just to show how "it
doesn't work".

Especially because often a re-run of the effect will be desirable when _some_
of the props change, not always the whole bag..

------
bhousel
Ah yeah, hooks are strange at first..

They didn't click for me until I read this netlify blog post:
[https://www.netlify.com/blog/2019/03/11/deep-dive-how-do-
rea...](https://www.netlify.com/blog/2019/03/11/deep-dive-how-do-react-hooks-
really-work/)

If you think of them as mostly just syntactic sugar for closure state
variables wrapped up in the module pattern, it's not so bad. (This is how some
of us have been writing D3.js code for years!)

------
mmckelvy
Long time React user here, have started experimenting with hooks. My general
sense is the useState hook is a pretty neat idea, but useEffect and friends
need some work. Definitely doesn't have that same "completely makes sense,
this is a great API" feel that I typically associate with React.

------
spion
The most fascinating thing about React Hooks is the perceived false dichotomy
of hooks vs old class API. The old class API was pretty bad and could have
been improved without changing the paradigm. Take componentDidMount and
cdUpdate: they could have been replaced by this.onMountOrUpdate(fn) : that
would have both solved the ergonomic issues and allowed multiple event
listeners to be set up by multiple custom 'component enhancers' (the
equivalent of custom hooks).

The market is ripe for a React like framework that keeps JSX and first class
components but goes away with hooks in favour of a couple of event listeners
and stuff like this.getContext(ContextName). Maybe also add MobX to easily
solve state management. Vue is pretty close except JSX / first class
components are an afterthought.

------
mjpuser
I think the part that is hard to grasp is that React essentially has it's own
runtime tangled with JS. With the introduction of hooks, there are non JS
things going on, which is why React relies on the quirk of having the same
order and number of hooks in your component. It also has Suspense which allows
you to exit from the render function and return to that spot, which is
definitely not a feature of JS. So yea, it's weird. I think the interesting
question is trying to figure out what this means for the next version of
React. I would like to see if it takes a page or two out of Svelte's book.

~~~
zbuttram
There are no "non-js things" going on. I'll grant that they're doing some out
of the ordinary things in order to support hooks and suspense, but it's still
just JavaScript.

Edit: If you want to see how hooks are implemented without needing to
understand the React codebase, Kyle Simpson has a project that provides hooks
for non-React functions, the implementation is all in one file:
[https://github.com/getify/TNG-Hooks/blob/master/src/tng-
hook...](https://github.com/getify/TNG-Hooks/blob/master/src/tng-hooks.src.js)

------
stephen
Great post. I've also been ranty about hooks lately but am admittedly also
just learning more ins/outs of things as I go.

That disclaimer aside, my biggest gripe is that I think hooks _could_ have
been done in a "works from both OO and FP components" manner, so that all of
these new (legitimately) "amazing to use b/c they're not HOC" APIs like the
apollo hooks/etc. could be used by both types of components.

Instead, because hooks are they only non-terrible way of using libraries
(again say apollo), users/codebases are basically forced to convert their OO
components over to FP.

Specifically, to me the primary innovation of hooks is not "reinventing OO
back into FP", it's "the ability for reusable code to attach itself to the
component lifecycle".

I.e. a hook can know when componentDidMount/componentDidUpdate/etc. happened,
and do the right thing. That's the primary innovation of hooks, IMO.

That would be extremely useful for OO components too, and also very doable,
like just expose a component.addComponentDidMountCallback(...) type methods
(or component.addEffect(...) or frankly even useEffect could do this b/c React
implicitly know which component is being invoked right now).

With something like this, I think all of the "currently-FP-only" hook
libraries could have "OO-based" equivalents, that are just as pleasant to use,
and users could choose which paradigm they preferred on their own.

BUT, the biggest annoyance is that libraries would have to maintain both "FP
hook" and "OO hook" versions, b/c current/FP-only hooks API didn't consider OO
components a constituent in the design process.

(Specifically the only deal-breaker/breaking-API-change to use FP hooks from
OO (if React wanted to allow this) AFAICT is that useState returns a tuple of
[value, setter] instead of a State interface with getter/setter methods. If it
returned a State getter/setter, then the useState could be invoked outside of
the OO render() method, but then inside of render state.get() would return the
current value. AFAICT all of the other hook APIs are already "OO-compatible".)

~~~
tyri_kai_psomi
I view the draw away from OO as a feature and not a bug. Classical OO patterns
should have never been introduced into JavaScript, and it had a just fine
object model, that no one ever took the time to understand properly, for those
small use cases it was called for. Emphasizing the functional aspects of
JavaScript, it's clear strength, is the right call.

It just seemed like it was thrown in there because Java and C# developers who
were increasingly being forced to use JavaScript begrudgingly just couldn't
live without their "class" keywords, so they took to the forums to make
JavaScript more like a "real" language.

~~~
shantly
> it had a just fine object model, that no one ever took the time to
> understand properly

Plenty of the people who dislike Javascript's prototypal inheritance model and
(relatedly) scoping rules do understand them.

------
servercobra
I generally like writing hooks. They're fairly straightforward to understand
(until they aren't, but that hasn't bitten me often yet). However, reading
other people's hooks is a lot more mental overhead than the same class
methods, IMO. Either you have strict coding standards around them (which are
pretty hard to implement with automated tools, so hopefully your code review
process never lets anythign slip through) or comprehending someone else's code
takes longer. For that reason, I've stuck with classes for the time being.

~~~
wilsonrocks
This seems like a fair point about other people's custom hooks. An important
situation where naming helps so people can at least see what they do, without
worrying about documentation

------
duxup
I love hooks. They've simplified a lot of components with state that don't
"need" to be classes.

I have run into a sort of useEffect hell at times that makes me wish for the
old life-cycle components as visually I find them easier to comprehend in very
"active" and more complex components. But honestly I suspect that is because I
don't quite understand useeffect well enough.

------
Waterluvian
The TypeScript boilerplate that hooks eliminate for a react redux app is just
insane. I don't think I can ever go back. For the slight bit of magic that
make hooks work, you end up with such a concise function that describes the
important parts and not the boilerplate.

They're not perfect. To each their own opinion. But they are what ES6 did for
me to the language landscape.

~~~
acemarke
Glad to hear it!

I just wrote a tutorial that shows how to use Redux Starter Kit, TypeScript,
thunks, and React-Redux hooks together. Should hopefully be a big help, for
the reasons you described:

[https://redux-starter-kit.js.org/tutorials/advanced-tutorial](https://redux-
starter-kit.js.org/tutorials/advanced-tutorial)

------
cipinistor
When Hooks are not properly understood, blog posts like this one make hooks
look bad. However, that is just an error from the author, which results into
unnecessary and overly complicated "solutions".

Yes, Hooks take a bit of getting used to and until you get them they will be
... weird. I did a few mistakes trying hooks until I actually "got" them (the
fact that I tried to use hooks without actually understanding them certainly
didn't help). But learning to do them right was certainly not harder than
learning the quirks of classes.

In the beginning I thought they complicate the code unnecessarily.

Until I realized they can just be extracted into custom hooks.

The real power of hooks, besides the fact they are declarative!, is
composition and by means of composition they can be abstracted away as custom
hooks.

React is all about declarative UI composition but lacked the “primitive” for
having stateful logic composition in an elegant and declarative way.

Until hooks!

------
koz_
Hooks are great! I can sympathise with those suffering from JS fatigue, but I
don't think they are merely a prettier/different syntax for doing the same
thing, they are a significant conceptual simplification. This:

`const { data, loading } = useFetch("/query", {page});`

is not only shorter than the corresponding slew of lifecycle method
implementations that would be required in a class component, it's also much
more direct and readable. Trying to recover the intent of code by reading the
implementation of various imperative methods is painful and error-prone,
whereas it's hard to imagine how the above could any more effectively
communicate the intent - every single token is meaningful.

------
sebringj
From your complaint of deep comparisons in hooks, you should not be doing deep
comparisons though which is the point of immutability in checking refs which
is the whole craze of redux but craze meaning warranted in this case. In plain
classes with redux, you usually check against a simple property or ref change
anyway.

------
Pabblo001
Since hooks introduction, I fell in love with React. I always use useState,
useEffect, useContext, useReducer...

I remember the pain building an app with redux and constant mapToState....
that was nightmare! With hooks it's so easy now.

~~~
acemarke
Please check out our new Redux Starter Kit package [0]. It includes utilities
to simplify several common Redux use cases, including store setup, defining
reducers, immutable update logic, and even creating entire "slices" of state
at once

The React-Redux hooks API [1] also requires less code that `connect`.

I just wrote a tutorial for RSK that shows how to use it with TypeScript,
thunks for async, and React-Redux hooks [2].

[0] [https://redux-starter-kit.js.org/](https://redux-starter-kit.js.org/)

[1] [https://react-redux.js.org/api/hooks](https://react-
redux.js.org/api/hooks)

[2] [https://redux-starter-kit.js.org/tutorials/advanced-
tutorial](https://redux-starter-kit.js.org/tutorials/advanced-tutorial)

~~~
mikewhy
(note this is not directed at redux, react-redux, or the wonderful redux-
starter-kit library. I'm also a huge, huge fan of how createSlice combines
action constants, action creators, and reducer handlers, all in one.)

Those react-redux hooks just exemplify the issues I have with hooks.

Yeah, potentially less code, but with more (and in some instances, completely
unheard of) gotchas, more that the developer has to do to keep parity with not
using hooks, and certain things dropped entirely.

I'm super interested in this discussion. I've been using React for years, and
it's been smooth sailing. But somethings up with hooks, and I haven't been
able to put it into words.

~~~
acemarke
FWIW, the "stale props/zombie child" issues described in the React-Redux hooks
docs [0] really have nothing to do with the hooks themselves. It's a
combination of:

\- The long-standing problem of trying to synchronize an external synchronous
state container with React's async rendering cycle

\- That our existing solution for this problem requires overriding values in
context for connected components

\- The fact that context usage _require_ rendering a <Context.Provider> to
update a value

\- The fact that hooks themselves do not do any rendering

So, the solution we have for avoiding stale props only works with `connect`.
It's not that the hooks themselves are problematic or have inherent gotchas,
it's just that hooks don't offer the specific additional capability we would
need to implement that same solution in both places.

A user just put together a _fantastic_ article that dives deeper into this
specific problem, and recaps how each version of React-Redux tried to solve it
[1]. Highly recommended reading if you have some time.

[0] [https://react-redux.js.org/api/hooks#stale-props-and-
zombie-...](https://react-redux.js.org/api/hooks#stale-props-and-zombie-
children)

[1] [https://kaihao.dev/posts/Stale-props-and-zombie-children-
in-...](https://kaihao.dev/posts/Stale-props-and-zombie-children-in-Redux)

~~~
mikewhy
Thanks for the links! That blog post is great.

I've encountered the issue before, but never knew the name. After bumping into
it a couple of times I just changed up how I use react-redux.

------
cooervo
interested in hearing more people experiences with React Hooks.

~~~
jerrycruncher
I've completely stopped using class components after spending some time with
Hooks in a small-to-mid-sized application.

The big wins for me were:

\- passing an empty array as the last argument of useEffect makes useEffect
work in a similar fashion to the old ComponentDidMount. You can have any
number of useEffect invocations in a component, and for a component that is,
say, loading data from two different sources, I find having two discrete
useEffects loading just what they need much more clean/intentional than
putting everything into a single lifecycle method.

\- using Hooks with Context almost completely fills the giant state management
hole that has been (imo) hampering React since its inception. Hooks + Context
is a cleaner and more comprehensible solution than React + Redux for any
application that has a reasonable amount of state complexity. For data-heavy
applications, Redux may still be a good choice, but for everything else, the
Hooks + Context combination is hard to beat.

~~~
fabian2k
How do you handle the drawback that changing the context will rerender _all_
components that use the context? Putting too much state into a single context
does seem like it could cause performance issues, especially with state that
changes often.

~~~
jerrycruncher
I agree that if you had a large (in the dozens, if not hundreds) number of
dependent components, it could be an issue. However, I've noticed no
performance degradation with my usage -- I use a top-level AuthContext
component to handle user data/login state, and another for access/caching of
the app's main data.

In a single view (for lack of a better term), I'd guess the largest number of
components that access either context is six.

------
peternicky
Not to sound like a jerk but I cannot help but think this dude is whining
about very petty issues. I read the article and found it to contain very weak
arguments.

I totally can relate to the frustration when learning new stuff, especially
when you have done things one way for years. Personally, the first month or so
that I used hooks in react, it wasn’t pleasant, mostly due to me being
uncomfortable with the additional load of learning this new convention.

Suck it up buttercup ;)

~~~
cdeutsch
> Personally, the first month or so that I used hooks in react, it wasn’t
> pleasant

I didn't feel that want when picking up React originally, but I do with Hooks.
That's a giant red flag in my opinion.

