I suggest doing a search and replace - "shadow dom" -> "virtual dom". The shadow dom is a different beast altogether. it is part of the web components standards and has to do with styles encapsulation. You are not the first one to mix the two terms but still :). Good arguments against the virtual dom (you mentioned some here, I know it isn't your main point): svelte.dev/blog/virtual-dom-is-pur...
With hooks there is useEffect that is supposed to replace componentDidMount and componentDidUpdate and can be forced to run only once (by providing it with an empty "dependencies array"). There are also a host of other hooks (useMemo, useCallback, ...) who try to make up for the ridiculousness of running everything on every render
I agree with the sentiment expressed here but I think it is not all because of the declarative syntax. It is a combination of things:
JSX - other declarative frameworks that don't use jsx (like Svelte :)) won't allow putting fancy javascript within the declarative description of the view
All logic should reside within the render function - this is a problem whether you are using declarative or imperative syntax. You gave good examples for it.
Time is not a thing - this is where declarative syntax can be get in the way because it simply ignores the existence of time. Sometimes it's fine. Sometimes not so much. "A then B than maybe C or maybe D" is by definition imperative and cannot be gracefully (or in some cases at all) expressed declaratively (example for a "solution": Redux thunk 😩)
At the risk of sounding like a fanboy (I am getting a more realistic view of its strengths and weaknesses these days so I don't consider myself a fanboy), I will mention Svelte again. I find it interesting that it takes a different approach. Some of it is declarative on steroids (reactive variables, basic declarative animations, template constructs for if, elseif and else, each and await) but some allows you to go full-on imperative (a good example is the "actions" feature which lets you manipulate a dom element directly or the low level control you have with custom transitions and animations). I guess it is as you said - the secret is in finding the perfect balance.
3-6) Agreed on all points, but I'm particularly nodding along to #6. Perhaps that encapsulates my "declarative angst" more than anything in my post: the declarative blindspot to time. As much as I love me some React, it can still drive me a little batty sometimes when I want to use The New Hot Package that someone told me about on NPM, and then I start looking at how it purports to help with all this complex logic, and its answer is: "Just drop this component here." And I'm thinking, "Wait a minute. I can't just drop the component there. There's gotta be logic governing when it gets used or what happens before it gets used and what happens after it gets used." That's why I used the example of APIs. Because IMHO, an API call must be a tightly controlled thing. It needs to happen at a very specific time - and no other time. Bundling an API call into a declaratively-called component and accepting that it will call (and re-call) an endpoint whenever the component's rendered just isn't acceptable to me.
I agree.
I think it was Rich Hickey who said in one of his talks that modern tools, frameworks and even programming languages seem to be optimised for beginners. Any tool that can't get you up and running in 3 minutes by copy pasting some examples into your code is automatically dismissed. Frameworks compete over which one makes it easier for an absolute beginner to build a toy version of a TODO list.
While I do appreciate it sometimes when I build some throwaway prototype or just want to play around with a tool to see what it's about, understanding is still the only real currency of our trade.
Amen. This was always my problem with Ruby on Rails. Everyone would show you this crazy-simple example of how they could build a RoR app from scratch in minutes. But if you start adding custom requirements (like, ohhhh... every real world app ever) and you can no longer settle for the "default" way that RoR wants to do everything, pretty soon that app takes just as long to build, and it's just as complex, as any app built in any other language.
1) Good catch on the shadow/virtual DOM thing. I've been using the terms interchangeably for quite some time. So it's good to have someone point out that logical oversight so I don't continue repeating the error!
2) I'll probably be doing more of my future examples in Hooks, since I'm writing more of them for work and that's where my minds been turning to lately. But AFAIK, useEffect doesn't particularly solve these issues at all? As you've pointed out, it just provides a Hooks equivalent of componentDidUpdate and componentDidMount?
I meant that even though useEffect (like every hook or anything else inside the render function) runs on every render it can be prevented from running its cleanup and effect code over and over again by passing in an explicit dependencies array (it still redundantly compares the dependencies on every render cycle to decide whether it needs to run but that's cheaper).
For further actions, you may consider blocking this person and/or reporting abuse
We're a place where coders share, stay up-to-date and grow their careers.
My two cents:
useEffect
that is supposed to replacecomponentDidMount
andcomponentDidUpdate
and can be forced to run only once (by providing it with an empty "dependencies array"). There are also a host of other hooks (useMemo
,useCallback
, ...) who try to make up for the ridiculousness of running everything on every renderAt the risk of sounding like a fanboy (I am getting a more realistic view of its strengths and weaknesses these days so I don't consider myself a fanboy), I will mention Svelte again. I find it interesting that it takes a different approach. Some of it is declarative on steroids (reactive variables, basic declarative animations, template constructs for
if
,elseif
andelse
,each
andawait
) but some allows you to go full-on imperative (a good example is the "actions" feature which lets you manipulate a dom element directly or the low level control you have with custom transitions and animations). I guess it is as you said - the secret is in finding the perfect balance.3-6) Agreed on all points, but I'm particularly nodding along to #6. Perhaps that encapsulates my "declarative angst" more than anything in my post: the declarative blindspot to time. As much as I love me some React, it can still drive me a little batty sometimes when I want to use The New Hot Package that someone told me about on NPM, and then I start looking at how it purports to help with all this complex logic, and its answer is: "Just drop this component here." And I'm thinking, "Wait a minute. I can't just drop the component there. There's gotta be logic governing when it gets used or what happens before it gets used and what happens after it gets used." That's why I used the example of APIs. Because IMHO, an API call must be a tightly controlled thing. It needs to happen at a very specific time - and no other time. Bundling an API call into a declaratively-called component and accepting that it will call (and re-call) an endpoint whenever the component's rendered just isn't acceptable to me.
I agree.
I think it was Rich Hickey who said in one of his talks that modern tools, frameworks and even programming languages seem to be optimised for beginners. Any tool that can't get you up and running in 3 minutes by copy pasting some examples into your code is automatically dismissed. Frameworks compete over which one makes it easier for an absolute beginner to build a toy version of a TODO list.
While I do appreciate it sometimes when I build some throwaway prototype or just want to play around with a tool to see what it's about, understanding is still the only real currency of our trade.
Amen. This was always my problem with Ruby on Rails. Everyone would show you this crazy-simple example of how they could build a RoR app from scratch in minutes. But if you start adding custom requirements (like, ohhhh... every real world app ever) and you can no longer settle for the "default" way that RoR wants to do everything, pretty soon that app takes just as long to build, and it's just as complex, as any app built in any other language.
1) Good catch on the shadow/virtual DOM thing. I've been using the terms interchangeably for quite some time. So it's good to have someone point out that logical oversight so I don't continue repeating the error!
2) I'll probably be doing more of my future examples in Hooks, since I'm writing more of them for work and that's where my minds been turning to lately. But AFAIK,
useEffect
doesn't particularly solve these issues at all? As you've pointed out, it just provides a Hooks equivalent ofcomponentDidUpdate
andcomponentDidMount
?I meant that even though useEffect (like every hook or anything else inside the render function) runs on every render it can be prevented from running its cleanup and effect code over and over again by passing in an explicit dependencies array (it still redundantly compares the dependencies on every render cycle to decide whether it needs to run but that's cheaper).