> If a linter is required to tell me when I'm writing a bug that is not immediately obvious, that is a failing in the framework
yep. They also commandeered the entire use* namespace just so they could get lint to warn when you put a hook outside the start of a function. Hacks on top of hacks.
Edit: after writing this I went and read the article. Same scenario I was bitching about lol
React was easy coming from jQuery, Backbone other frameworks at the time.
With effects, i've read the docs many times. I still don't fully understand how it's supposed to work.
I don't seem to get the feeling / abstract concept behind it and it still surprises me at times when it fires / or not.
Too much magic for me. But maybe im getting old :).
In contrast, useEffect() is "exactly what I want" without having to figure out what combination of lifecycle methods to implement.
I'll grant you that this could have been done differently - I'm not a fan of the "order of calls represents hidden state" mechanism for hooks. It's possible to imagine a different API for class components that provides ergonomics similar to useEffect() and useState(). But hooks are still an improvement over the old class component API.
The main issue is that it's not a native language construct, but a mini-dsl sort of so you need to have this state machine in mind even thought it's implicit and hidden from you.
Instead of reading the docs, you might want to search online how to write hooks from scratch. It's one of those concepts that needs to click.
I've built some really complex frontends with React. But now here I was, struggling with setInterval, ha.
I would argue that the real footgun with hooks is the case where a `useEffect` call inadvertently gets triggered on each render because one of its dependencies, passed through another hook, changes identity on each render. It can get quite maddening, and in many cases you don't notice it until someone points out the resulting performance issue with your app. The solution, of course, is `useMemo` and `useCallback`, but it's not intuitive and it can be easy to miss from time to time in a large project.
useEffect(() => {
const interval = setInterval(() => {
// whatever
}, 1000)
return () => {
clearInterval(interval);
}
}, [])Took me at half a week at least and I felt like a god after. Then I realized this was all phenomenal waste of time and I decided my next job was going to be cloud and backend focused. Only in the js world can you realize immediately as soon as your done that it's effectively worthless programming hassle.
The right way to do that exists in Elm. But I do not think there is a way to translate that into JS without requiring either a lot of boilerplate or very messy code
I've been working on a quite complex React codebase for 5 years now - it's not the biggest but still not so small. I was there on day 1. The team that works on it now full time is ~15 devs + 10-15 doing some minor stuff from time to time.
We've started using hooks about 1 year after they introduced them. Before we were very deep into redux and redux-saga. Now most of our codebase uses only hooks for most of the things we did with redux before - there are still some redux but most major parts are migrated to using hooks and contexts. It is probably the best decision we made after switching to TS. Most of our codebase is still very easy to maintain. Last year I went on a paternity leave for 6 months and I was pleasantly surprised how easy it was to adapt back.
Edit: forgot to write about Elm. I like elm a lot -even though I don't agree with how it's managed-. I even organized a local elm meetup :) But I think while it is very good in theory, it's not too easy to scale especially if you plan on hiring more devs. Also the way effects and data is completely separated from the view is not very ideal for bigger projects. You either end up having to touch too many files for a single feature or have incredibly big files.
There are other ways to achieve similar. You don't end up with "big mess of hard-to-follow spaghetti code", you might end up with a "large amount of unfamiliar-looking code". Getting better at reading a larger-than-anticipated amount of unfamiliar code takes a bit of practice, then it isn't a problem. And then you have all the benefits of Elm with zero problems.
The actual hard thing about code is managing complexity, and working with "it just works" magic when it doesn't "just work".
I agree Elm has some flaws, and there is an initial up-front time investment which is unsavoury to many.
If you compare this to Halogen (https://github.com/purescript-halogen/purescript-halogen/blo...) where you still have purity but can set up subscribers and listeners from any component. It's much easier to use and for some components like dialogs, it's much simpler. And this actually isn't the best example because with the latest Halogen, Portals (https://github.com/purescript-halogen/purescript-halogen/pul...) was introduced so you can launch a dialog on the spot instead of even needing to communicate between them at all.
This is my anecdote though. And I've been away from Elm long enough now (around 1.5 years) that I've forgotten all the specifics.
That said, I still preferred React.createClass so I guess I'm somewhat off the beaten path when it comes to React.
My take is that if a feature requires a linter to be properly implemented then it's obviously giving the developer too much rope to hang themselves with.
Also it appears that they were introduced mainly for performance, but for some reason sold as the new "better" way of writing applications.
I actively avoid React and its ecosystem, because I believe there's just too much FOMO and "fashion"(for lack of a better word) in what drives its development and not enough meritocracy.
Those linter warnings with React hooks show just how much of a disaster it is. All of the "simplicity" that comes with hooks is just complexity that is now completely out of sight, and only appears once the code is run in a linter. That is even worse than having the complexity in the code.
You can write really performant software in React, but ergonomic (beyond stockholm syndrome) I would not call it.
It's also difficult to implement quality software engineering principles in a React application such that an application is maintainable, glacable and easy for someone new to a project to pick up.
The flexibility in its toolchain is nice, however
I still like using them however. I had a few issues when trying to do more abstract code.
They are highly, deliberately, emphatically procedural.
The order they are called matters! The time of when they are called matters! The number of times they are called matters! You get a different result from calling the same hook with the same arguments at different times! You get different results if the call site for them is in different places!
They do enable you to do some things in JavaScript that are more easily enabled with higher ordered function stuff in functional languages, but there is nothing ‘functional’ about how hooks work or how they are used.
And that’s okay! ‘Functional’ doesn’t automatically mean ‘better’ and ‘procedural’ doesn’t mean ‘worse’. For what they do, hooks (considered as the entire hooks ecosystem including linting extensions that help enforce the rules as if they were syntax errors) are a very clever extension within JavaScript syntax that let you pull off some very neat separation of concerns in a reactive code model.
‘Functionalness’ has very little to do with whether hooks are good or bad.
Because when function components first came along that's what the whole of React was supposed to be: "functional" UI, using things like redux or mobx for state. Plenty of guides still use that terminology even though React's homepage now uses "declarative".
That said I think they were always misusing the term, I remember this because I used to complain to people that react itself was declarative, not functional, and just gave the option of writing in a functional style.
I do not want this handled at the framework level though. There are plenty of times in my day-to-day where that linter is wrong. If I were to add one of the dependencies (it's sure I should add) my component would re-render over and over. Sure, one could argue, "well, then you've poorly architected your code"... but THAT is where I feel like the failure occurs. Having to do write my code to please a paradigm. What that means is I only "sorta agree" with the design trade-offs. And much like Ruby on Rails, you either go all in, or spend your days hating the framework.
I do worry that Solid also has these "If you know, you know" edges though. So I'm trading looking at a function and assuming it'll run over and over with, looking at a function and thinking, "how can I make this thing run again when it needs to?" I'm not saying it's wrong, it's just another piece of tacit knowledge one has to learn when adopting a new framework.
If I know I have a dependency I want to ignore, to achieve a certain result. Then I have a way to achieve a particular data flow. One can _say_, that's wrong but it's a deterministic way to achieve that result. Calling it "wrong" delves into the weirdness of hooks. Love them or hate them, they create patterns which must be learned and mastered. And even then... they can still be confusing. Except for on the internet obviously, here we find people who never have problems with them :)
On the JS/TS planet there's https://cycle.js.org , which comes close.
Looks even better than Solid IMHO.
Isn't the point of static analysis (including linters) that they catch those kind of bugs? Having that little red underline (or console warning) saves a lot of pain.
Hooks have completely changed the way I write React code. It's so much easier to test and reason about. Really the only problem is that the guardrails aren't more heavily enforced.
Hooks are a syntactic element of react code. Calls to them aren't legal inside conditionals or loops.
Full linting support smooths over that rough edge just as effectively as babel handling ?. syntax smooths over its absence in certain JS runtimes.
Solid is nice and _seems_ to fix the issues with hooks, but as another comment mentioned, the challenge is with building at scale. It's unclear to me how this scales and where the sharp edges are.
React IMO trades off performance in exchange for ergonomics. These ergonomics bear fruit early on, but you start dealing with this debt very quickly. As "nice" as Redux is, I shouldn't need it so early. React is designed in a way that results in pretty terrible performance. I once wrote a React app, and discovered perf issues 2 weeks in. Any UI framework I used in the past would have scaled beyond this point without having to have the data layer rewritten. Frameworks of the past also had what seemed like way less "magic".
I totally accept that it's seriously nice to write, but how many trees has React alone burnt?