[NOTE: I've since written an update to this article with an improved solution. It can be read here: https://dev.to/bytebodger/streamlining-constru...
For further actions, you may consider blocking this person and/or reporting abuse
In this case, I would use
useRef
instead ofuseState
to omit an unnecessary render cycle, even though it's a small one.Good point! I haven't really messed around enough with
useRef()
. This works better.Hey @bytebodger I am new to hooks, I previously only used components where I used to rely on the constructor. I wonder if I'm doing it right... since I really miss the constructor functionality, I created two hooks: useCreateOnce (returns a value) and useRunOnce.
But now I'm using these 2 in many places so I wonder if there isn't another way, which follows more React hooks "intended" philosophy? Or maybe I shouldn't worry that much?
dev.to/spukas/4-ways-to-useeffect-pf6
This article right here on Dev.to is pretty handy - so much so that I stuck it in my reading list. A constructor is ultimately a lifecycle method. And in Hooks, there is exactly one lifecycle method -
useEffect()
. As the name implies, there is no such thing as auseEffect()
call that runs before the component renders (since, an "effect" has to happen... after something else). And as the article above implies,useEffect()
can actually be used four different ways - although I don't personally believe that any of them are intuitive just by reading the names/arguments.would lazy initialization of useState work as a
useSingleton
e.g.
A more fleshed out example:
Gist
Yep. That works as well!
For me the fact that all of the hooks are invoked every time and have to bail out if they don't need to run (basically by using an "if" statement explicitly like you've demonstrated or implicitly using dependency arrays) is hugely offensive. So much unneeded work and wasted electricity plus wasted brain cycles (should it run every time or not...)
The virtual Dom is already the king of wasted CPU cycles (diffing all of the things when barely anything has changed) but at least it doesn't put a constant mental tax on the developer. Until you need to start manually preventing it from updating every time that is.
I think you know this already, but I couldn't agree with you more. One (perfectly valid) response to this entire post would be, "Dooood, if you're so in love with constructors, then just write class-based components." But as (I assume) you've experienced already, sometimes you find yourself on a project / assignment / whatever where Pattern X is already the "accepted norm". And you're thinking, "Well... I usually use Pattern Y, which has Feature A. But, I don't see any analog for Feature A in this new pattern."
For the first time since they were introduced in Oct 18, I find myself on a team where we are (and plan to continue) cranking out functional components - with lots-and-lots of Hooks. So, in that environment, I'm trying to figure out the best way to adapt to "Pattern X" (in this case, Hooks) without losing some of the key features that I enjoyed in "Pattern Y" (in this case, class-based components).
I'm also trying, oh-so-hard, to not be that guy. You know that guy. He's the one who's always done things a "certain way", and when the team says, "No, we're gonna do this new project in a different way," he sits in the corner and pouts cuz he really just wants to do everything the same way he's always done it in the past.
Could you give an example where a constructor would be useful?
Unfortunately using a constructor seems to be the only way to go if you are using Redux and you don't want to blink a "no data" message or stale data before a fetch action is dispatched in useEffect. Having worked with other frameworks, I am simply amazed by having to do this ugliness in React...
Interesting/related note: This article has quietly gathered more views than anything else I've written. Unlike most of my articles, that have a certain "splash" for a few days - and then are rarely read again - this article continues to get a steady stream of traffic.
What's the point?? Well, it would seem that there are a lot of other people out there who are switching to Hooks, then saying, "Wait a minute. How do I create a constructor with Hook??", then they start googling and end up on my article. (And there seems to be very few other articles out there on the same topic.)
So while it may indeed be "ugliness", I surmise that there are many others who are confused/annoyed by the (
FALSE
) idea that you can simply useuseEffect()
to replace all of the previous lifecycle methods, and there's no logical reason to use the constructor functionality that we had in class-based components.Thank you for writing this article! I thought I was missing something by always having to skip renders with a flag which is set only after a fetch is started in useEffect or trying to do fetch calls in something like your constructor. Seems that React devs have missed the point that sometimes you need to have a cause before you can handle the effect...
Having spent years working with the lifecycle methods that are available in class-based components, I'll be the first to tell you that they can, at times, cause major headaches. But the Hooks team seems to have decided that the way to cure the headache is to cut off the head.
I'm always willing to learn different ways and adapt, but i used to use a react constructor to pre-prep a lot of data, even for static websites. For instance i might translate a linear array into a 2d one better suited for defining a layout. Things like that. I guess i could do it another way but they all just seem like added complexity.
I will add here that, even in the documentation for class-based components, there's a general assumption on the part of the React team that constructor functionality is limited to initializing state. In my personal experience, I know that, on numerous occasions, I've found it prudent to handle other bits of logic in this part of the component life-cycle. Specifically, there are times when I want to prepare variables that will be used in the component, but I don't want the updating of those variables to be tied to state. In other words, there are sometimes some variables that I want to live outside of the rendering process. When I need to do any pre-processing on said variables, the constructor is an ideal place to do so.
The easiest analogy is
componentWillMount
. Anything that anyone previously wanted to stuff incomponentWillMount
is a prime candidate to be put in the constructor. But don't take my word for it. This is directly from the React docs:So if you were using old-skool React, you might've had a handful of components that used
componentWillMount()
. Then, that was deemed to be unsafe, and the maintainers themselves said, "Now you should move it to theconstructor()
. But with function-based components, there is no constructor.Again, as I stated in the post, I'm not claiming that this is functionality that you'd need on all components. You won't even need it on most components. But the fact that we previously had
componentWillMount()
andconstructor()
signals that there are valid use-cases for it.I often face the same issue but it is easily solved with a useRef. I usually write a useEagerEffect hook that runs before rendering, but still only runs when the deps array changes.
The part I really agree with, though, is how react's docs (and those of many other libraries) make these sweeping assumptions that nobody could ever possibly need anything outside of their perceived use cases. The blind arrogance you mention really frustrates me!
You're spot-on about the
useRef
. In fact, in myuseConstructor
NPM package, I wrote it withuseRef
, rather than theuseState
approached illustrated in the article. There was another commenter on this thread that was gracious enough to point me in that direction.I have used hooks in up to 3 production projects but I can't find the use cases of this hook honestly.
Haha - well, I'm not trying to convince you to use it. I'm just pointing out some ways that you could achieve it if you do find the use case.
I don't know if I've ever had the occasion to actually write my own closure. That doesn't mean that there aren't use-cases to write closures.
Okay and funny enough, I use closures a lot of time e.g in factory functions.
And that's why I said that I consider the Hooks documentation regarding constructors to be arrogant. It starts from the (false) assumption that there's only one reason to ever need/use a constructor (to initialize state) and then it doubles down on that folly by stating that there's simply no need for them anymore.
With closures, I'm sure there are many devs out there like me who aren't using them often (or at all) in their code. That doesn't mean that we should make a global statement that they're not needed. And we definitely shouldn't do anything to remove support for them.
Ryan Carniato (SolidJS, MarkoJS) notes in: React Hooks: Has React Jumped the Shark? (Feb 2019):
He has a number of other pro-Hook (but not fanboyish) articles:
That last one explains where hooks do make sense.
The fit with React at this point is somewhat awkward - one has to wonder whether React is maneuvering into a position where ditching the VDOM becomes an option (to replace it with modern Fine-Grained change detection).
Oooh... these links look awesome. In particular, I love love LOVE the assessment that "Hooks are no simpler". I think this speaks to some of the frustration I've had with them, literally since the day they were announced. I'm not anti-Hooks. In fact, all of my current React dev is now Hooks-based. But I'm continually annoyed by some fanboys who act as though Hooks are self-evidently better, and everything else is clearly worse. They act as though the answer to, "Why Hooks?" is "Well... Hooks!!!"
The historical perspective in these articles is also awesome. I've made a few references in my previous articles to Knockout. It's amazing (to me) how many "senior" JS devs today don't even know what Knockout was/is. This author seems to have a very well-rounded approach to the whole thing.
I needed Deep dive: How do React hooks really work? (2019) before hooks made sense to me.
I appreciate this half rant, half instruction. Some of the workarounds to move to a hooks only react environment really are not all that clean or efficient.
Also just FYI: unless i'm mistaken and there is yet another way to declare functions, your const useConstructor variable is never initialized as a function.
In both cases where I illustrated
useConstructor
, it was defined above theApp
function.Yeah it's where you defined it that i don't quite understand and it throws errors for me. "Const declarations' require an initialization value."
Your one has:
Should it not be this? (which works)
I'm not trying to nitpick... i'm just uncertain of my own knowledge and the ever changing landscape of javascript.
Ahhh, yes. Good catch. I am missing the
=>
. Obviously, I didn't actually run these examples. I just typed them out. Thanks!I had a problem related to this topic: I needed a unique-id in my component. In order to avoid generating it on every update I did this initially:
However, that didn't help. The value of
uniqId
remained the same throughout all the updates, but the call togenerateUniqId()
was made on every update. I solved it like this:That made sure that
generateUniqId()
was called only once and not on every update.I just wanna say this is a great article, thanks for this really helped me out with solving the lack of a constructor use case.
Thank you - I'm glad it helped!
What about useMemo? It seems to work, what are the tradeoffs? Would it solve the constructor issue?
Can someone help me?
stackoverflow.com/questions/671299...
Its very helpful Adam