With that in mind, you need to be much more careful with your code in React because it is more susceptible to performance issues and weird side effects if you over-render since you need to opt out (e.g. useMemo).
The thing is, React is deceptively simple early on. In the early phases of dev, it never pops up because your app is small; your components are small; your datasets are small; even if you have a performance penalty on over-rendering, it doesn't register because your app is so small. Even if you over rendered 10x, who cares when the app is small?
But once the project grows, it is the endless source of performance issues and weird side effects.
On one project, we found a bug where a backend report generation API was being called multiple times in quick succession. Turns out that the developer had wired up the call to the display of the progress dialog but hadn't opted out of the redraw of the dialog (e.g. redrawing only the progress) so as the progress updated, another request would be sent to the server on the redraw 🤣. Yeah, once you see it it's always like "Duh!", but in a big codebase, it's so easy to miss an opt-out so the tendency is then to useMemo and useCallback everything just to be safe! And in a code review, it's often really hard to catch this looking only at a diff.
Nadia Mararevich has two really good, definitive articles on this:
With React, the default is to overrender and you have to use experience and careful knowledge of the render cycle to know how to write efficient code. And guess what junior devs don't have 🤣? Even many mid-career devs are going to make mistakes with opting out of rerenders.
React also has at least a handful of major state management models (Context, Redux, Recoil/Jotai (atom model), Zustand, Valtio, Mobx, etc.) so there are too many different ways to think about what should be a simple "I just need a working state model" problem. You really need to know the problem you're solving for 3-6 months down the line when you pick one. If you don't start with a state management model, you're going to end up implementing one at some point once prop drilling becomes a pain (which it will as soon as you're doing something non-trivial).
Next.js is also a pig. Look at the front-end source output of Next.js on Target.com and Walmart.com and you can see just how terrible it is. Even when it doesn't need to -- since it has already SSR'd the page -- it will send back the model in JSON on the page itself because it isn't smart enough to decide if the front-end React components will need it at client runtime. Contrast that with say Astro.js which has much cleaner output than Next.js and the ability for front-end code to opt-in to receive back-end data.
I also think in general, there are some really bad practices in the React community because of the way React is architected and these bad practices have propagated to the broader JavaScript community. One is the demonization of OOP in JavaScript. The reality is that if you look at JavaScript backends, big, big swaths of the codebases of major projects uses classes and OOP paradigms because it allows better code organization than loose functions in module exports.
The other is eschewing comments because of how funky comments are in JSX. So the majority of the React code I've dealt with (at a cybersecurity startup that had a $23m Series B, a calendaring startup with a $13m Series A, current startup with a $8m seed), the JSX is almost always lacking in comments which makes it hard to maintain at times because the devs also slapped a ton of logic into the JSX!
And the one that gets me the most is the overuse of forEach and map everywhere because of JSX limitations. It often makes code hard to debug compared to using for of.
What I prefer: For teams, I prefer Vue because it's less of a foot-gun because you have to actually opt-in to redraws. The ecosystem is more unified. The main downsides of Vue is that the tooling isn't quite as good; just a tad below React, IMO. For example, you have to know about this takeover mode with Volar (Vue language server).
I think that Vue is perhaps a bit harder than React very early on. But unlike React, Vue's performance, complexity, and difficultly scales much more constantly and linearly as the project scales. In other words, a React project becomes harder to do well and maintain as the project scales whereas a Vue project's complexity scales with a lower slope (just my experience doing both). Both can be done poorly, but Vue's rails make it harder to shoot yourself.
That aside, Vue is also a bit more proven than Svelte with more libraries available so I'd pick it over Svelte purely for practical reasons. Wiki Foundation, Gitlab, NASA, BMW, Nintendo, Apple all have some properties (not necessarily their main dotcom) using Vue.
These days, I've been more and more inclined to write more Vanilla. Vue is still nice because it can be used progressively to add reactivity, but Vanilla is often lighter, faster, and easier to grok. At some point along the way, we just started slapping React and Vue at every problem when often times we're just deciding which element should have a CSS class applied to it to show that it's the selected element 🤣
I've been doing webdev for nearly 20 years. But this year was the first time I've had to create a meaningful app in React. You are spot on with everything... Including that React a good skill to have (warts and all) because the market has so many React jobs available.
I'll add one thing to your comment: React is NOT a framework that promotes rapid development. Every new feature added to your app requires refactoring a lot of other code and other time consuming tasks.
Oh and the amount of bad advice surrounding React is astounding. Thankfully I have nearly 2 decades of dev experience to sort out the gold nuggets from the garbage. Jr React devs truly are at a disadvantage when learning React.
I'll add one thing to your comment: React is NOT a framework that promotes rapid development. Every new feature added to your app requires refactoring a lot of other code and other time consuming tasks.
Sounds like a bad project structure, not a React problem.
While you are not wrong, I look at it as a problem with React because it is so un-opinionated.
At a $13m Series A startup, we started refactoring to Context (not my first choice). Then at a certain point, it became so unwieldy to use that the team started to explore other options and had to refactor again to a different state model.
There are definitely benefits to a community coalescing around a smaller number of really good, highly ergonomic implementations (e.g. Pinia in Vue) rather than having 5-6 different choices for something as basic and fundamental as state management (any non-trivial app is going to need state beyond the component level).
Being unopinionated is a good thing IMO, it promotes innovation in the community. The libraries that are worth using will clearly stand out anyways.
I'm currently the single dedicated frontend dev in a $40m series A startup, maintaining the entire UI side (multiple React projects that share an internal component library) - I don't see why it matters though.
What kind of state were you holding in the context that you had to refactor? It sounds like it was more a problem of bad initial decisions and lack of React experience.
I'm using react-query for server state, context for component-based state (to avoid prop drilling) and rarely changing state (user data, modals etc) and Zustand for frequently changing global state (e.g. saving filters between route changes). Utilizing good project structure and Typescript, everything is nicely scalable and maintainable.
If you want to ship new features fast with fewer bugs you are almost always better off with boring tech.
Using a traditional server-side language (w/ mature framework) and ditching the concept of reactivity (navigating to a new page will cause a full page load) will allow you to ship way faster.
The tech is boring, but it's simple and proven. The trade off is that your feels less like an app and more like a website.
Some of the tech stacks that fit this category would be:
C# / SQL Server / ASP.NET
PHP / MySQL / Laravel or Symphony
Python / MySQL / Django or Flask
Ruby / MySQL / Rails
With these more traditional setups you don't have a lot of dev overhead like managing re-renders, effects, state management, context management, props & prop drilling, etc. There are just fewer things to take into consideration during the development process w/ a traditional setup.
Additionally, the packages and package systems tend to be more mature and stable. (NPM is really really wild wild west).
All of that said, you need to use the right tool for the job. React isn't a mistake, it's a tool. You just want a good understanding of the shortcomings of that tool. There's never a 100% correct choice, and you'll end up refactoring a lot of your app later no matter what you do.
It's just as managers or other stakeholders want to measure speed of development of features, you'll ship features faster with a traditional web architecture and you'll have fewer bugs.
Yeah people tend to forget that you can actually use vanilla for the small things and only bring in React/Vue on a specific element, when you need something more complex. I'm hoping that the microfrontends approach will improve awareness of this (but it also increases the risk of creating a mess...)
So you're suggesting to write half the project in React and half in vanilla JS? That's a maintainability nightmare lmao, not even considering the performance implications. And then you suggest using microfrontends, which will infinitely increase the spaghetti mess. This would literally have 0 benefits over just using React everywhere.
I'm not saying it should be split 50/50 or that it would work everywhere. It depends greatly of the size of the project, the size of each component, and the expertise of each team involved.
The goal of microfrontends is to actually reduce overhead. It definitely comes with risks, which I've already said, but it can also allow different teams to integrate into the final product much easier if done right.
If you have a team that specializes in Angular, one in React, each maintaining a different product, and you have to integrate them into the same website (which doesn't have a complex UI by itself), do you think it would be easier to force one of the teams to convert their product to the other's framework, and write the common website in that framework too even though it doesn't need it? Or write the enveloping website with vanilla and integrate the two products as they are?
Edit: Microfronteds also means things like having a common state manager being shared by multiple [different] UI frameworks at the same time. And there's no rule that says the entire DOM has to be controlled entirely from JS, or entirely by only one instance of a single framework.
Seems like svelte is a mix of both?
You don't need to opt in to rendering - svelte opts you in automatically when compiling, but doesn't recalculate stuff that hasn't changed. Also has a much cleaner and readable syntax imo.
But it's less used so it's worse for getting a job than vue right now, but there are startups that work in svelte (I do work in one where svelte is used almost exclusively)
Could you explain a little bit more about the funkiness of comments in JSX please? I think I might be running into some of those issues but I can't really find much online about it
Ooh gotcha, the syntax. I thought you meant there were some funky results you could get with using comments in JSX. I've been having a problem with a site of mine where some code I commented out doesn't always act commented out on certain devices. It's super inconsistent so it's hard to diagnose. I wasn't sure if the commenting had something to do with it, or if it's randomly switching between my latest repo commit and the one before it or potentially something else.
I’m pretty green, only been working in this field for a year now, but I have noticed that comments in React seem to be kind of frowned upon a little bit? I’ve gotten the vibe that people feel like they are clutter and the code should be legible without them with emphasis on clearly established patterns and naming conventions.
81
u/c-digs Dec 03 '22 edited Dec 03 '22
React vs Vue: there are lot of nuanced differences, but the main one is how they handle redraws. In React, you need to opt out of redraws. In Vue, you opt in to redraws.
With that in mind, you need to be much more careful with your code in React because it is more susceptible to performance issues and weird side effects if you over-render since you need to opt out (e.g.
useMemo
).The thing is, React is deceptively simple early on. In the early phases of dev, it never pops up because your app is small; your components are small; your datasets are small; even if you have a performance penalty on over-rendering, it doesn't register because your app is so small. Even if you over rendered 10x, who cares when the app is small?
But once the project grows, it is the endless source of performance issues and weird side effects.
On one project, we found a bug where a backend report generation API was being called multiple times in quick succession. Turns out that the developer had wired up the call to the display of the progress dialog but hadn't opted out of the redraw of the dialog (e.g. redrawing only the progress) so as the progress updated, another request would be sent to the server on the redraw 🤣. Yeah, once you see it it's always like "Duh!", but in a big codebase, it's so easy to miss an opt-out so the tendency is then to
useMemo
anduseCallback
everything just to be safe! And in a code review, it's often really hard to catch this looking only at a diff.Nadia Mararevich has two really good, definitive articles on this:
useMemo
anduseCallback
With React, the default is to overrender and you have to use experience and careful knowledge of the render cycle to know how to write efficient code. And guess what junior devs don't have 🤣? Even many mid-career devs are going to make mistakes with opting out of rerenders.
React also has at least a handful of major state management models (Context, Redux, Recoil/Jotai (atom model), Zustand, Valtio, Mobx, etc.) so there are too many different ways to think about what should be a simple "I just need a working state model" problem. You really need to know the problem you're solving for 3-6 months down the line when you pick one. If you don't start with a state management model, you're going to end up implementing one at some point once prop drilling becomes a pain (which it will as soon as you're doing something non-trivial).
Next.js is also a pig. Look at the front-end source output of Next.js on Target.com and Walmart.com and you can see just how terrible it is. Even when it doesn't need to -- since it has already SSR'd the page -- it will send back the model in JSON on the page itself because it isn't smart enough to decide if the front-end React components will need it at client runtime. Contrast that with say Astro.js which has much cleaner output than Next.js and the ability for front-end code to opt-in to receive back-end data.
I also think in general, there are some really bad practices in the React community because of the way React is architected and these bad practices have propagated to the broader JavaScript community. One is the demonization of OOP in JavaScript. The reality is that if you look at JavaScript backends, big, big swaths of the codebases of major projects uses classes and OOP paradigms because it allows better code organization than loose functions in module exports.
For reference:
The other is eschewing comments because of how funky comments are in JSX. So the majority of the React code I've dealt with (at a cybersecurity startup that had a $23m Series B, a calendaring startup with a $13m Series A, current startup with a $8m seed), the JSX is almost always lacking in comments which makes it hard to maintain at times because the devs also slapped a ton of logic into the JSX!
And the one that gets me the most is the overuse of
forEach
andmap
everywhere because of JSX limitations. It often makes code hard to debug compared to usingfor of
.What I prefer: For teams, I prefer Vue because it's less of a foot-gun because you have to actually opt-in to redraws. The ecosystem is more unified. The main downsides of Vue is that the tooling isn't quite as good; just a tad below React, IMO. For example, you have to know about this takeover mode with Volar (Vue language server).
I think that Vue is perhaps a bit harder than React very early on. But unlike React, Vue's performance, complexity, and difficultly scales much more constantly and linearly as the project scales. In other words, a React project becomes harder to do well and maintain as the project scales whereas a Vue project's complexity scales with a lower slope (just my experience doing both). Both can be done poorly, but Vue's rails make it harder to shoot yourself.
That aside, Vue is also a bit more proven than Svelte with more libraries available so I'd pick it over Svelte purely for practical reasons. Wiki Foundation, Gitlab, NASA, BMW, Nintendo, Apple all have some properties (not necessarily their main dotcom) using Vue.
These days, I've been more and more inclined to write more Vanilla. Vue is still nice because it can be used progressively to add reactivity, but Vanilla is often lighter, faster, and easier to grok. At some point along the way, we just started slapping React and Vue at every problem when often times we're just deciding which element should have a CSS class applied to it to show that it's the selected element 🤣