PS: I'm not a frontend engineer but I find this topic interesting.
Thanks!
PS: I'm not a frontend engineer but I find this topic interesting.
Thanks!
The one real edge I'll give React is much better Typescript support due to tsx essentially being a superlanguage of TS. Vue's composables are very good, but it falls apart a bit in actual template usage. Tooling is also better, but that's also because it's simply used much more so has had more investment into making the tooling good compared to Volar for Vue.
But in my opinion everything else surrounding Vue makes it superior. Signals are a better state management pattern, there aren't all the insane footguns that React comes with, performance is better out-of-the-box and is practically impossible to fuck up compared to React where it's hilariously easy to make even the simplest of apps be performance monstrosities, the documentation is (IMO, I find React's docs (yes I've seen the new ones) terrible) best-in-class, the gilded libraries like Pinia, Vue Router, VueUse are far superior to anything in the React ecosystem...
I could keep going, but having worked with both more or less equally, I'd choose Vue 10/10 times over React, no questions asked. I can throw a junior at the codebase and be 100% confident they'll make something that's more-or-less idiomatic Vue code, even with the Composition API which is less stringent than the old Options API, whereas with React they'll always need hand holding and I'll always need to explain why things are rerendering twice or running terribly or what useMemo does or what useEffect does (or doesn't) do...
Today, 33% of vue downloads in the last 7 days are for vue 2.
There was a lot of things that were nice in the vue world like vite and vuex, but I'd never recommend vue to anyone, especially anyone that wants a good typescript experience.
here's an example library button using .tsx in vue https://github.com/vuetifyjs/vuetify/blob/master/packages/vu...
Pinia is Vuex, it was made by the same people specifically for Vue 3 due to otherwise having to introduce a lot of breaking changes and is a lot simpler than VueX was, as it leverages the composable pattern and gets rid of the need to do things like `mapGetters`/`mapActions`. And VueX 4 is still an option for those that prefer that approach.
> ... class mixins
Those were a pain point, but no longer relevant in Vue 3 as mixins have been deprecated. Again, composition takes its place and is in general much more powerful while being simpler. For a great example of what composables can achieve, I'd recommend taking a look at VueUse (https://vueuse.org/)
> Today, 33% of vue downloads in the last 7 days are for vue 2.
Another way to look at that is that the majority of the community is on Vue 3 :)
> If you want to use vue with a .tsx file you might as well use react.
`.tsx` is very much a personal preference thing and isn't really considered idiomatic despite Vue having support for it (unless you're a library author like Vuetify that you linked). I personally can't stand working with `jsx` and find Vue SFC's superior, and again, typechecking these days is much better than it ever was and will work just fine in 95% of situations. Especially with things like component generics being introduced, it's only gotten better and actively getting better.
I'd highly recommend you give Vue 3 a try with an open mind, because things have only gotten more powerful while getting simpler since the Vue 2 days.
I have the exact opposite experience, I find Vue hilariously bad to the point of being repulsive. Now what?
It's harder to do poorly and even when you do, it doesn't punish you the same way that React does.
Native development is definitely a pain point, unfortunately there's few options other than React Native there. Problem being that React is backed by Meta, so obviously it has a lot more money being thrown at it compared to competitors like Vue or Svelte.
There are certainly more UI libraries available for React than any other framework [1]. But do you think that these are also clearly better? What would be your go to framework for React? To me, it seems that the trend is going to framework-agnostic or multi-framework libraries anyway (e.g. Ark UI or Zag).
But gun to my head, Shadcn would probably be my choice. For Vue it'd be PrimeVue. Those are the two highest quality ones I've tried in small projects, so no clue how they scale in real-world projects.
That's doing a *lot* of heavy lifting here. That's like saying "D is infinitely better than C++, except for available libraries".
While my current Electron personal project will probably use Vue because I want to learn it, the change in libraries (and lack of plug-and-play support for whole companies' provided frameworks) is a real barrier to entry for a lot of work.
There are millions of developers happily using react every day. They just don't come onto HN to complain about the "woeful state" of frontend.
If building a SPA site with vite use tanstack/react-query and react context. There are other great libraries like zustand and jotai that can make sense in certain kinds of more complex applications.
const [name, setName] = useState('blastonico')
...
setName('nailer')
You do: let name = 'blastonico'
...
name = 'nailer'
Also a single .svelte file includes everything you need for a component (HTML, JS, CSS), so it's easier to manage.I get that assigning variables is easier to understand, but it's way, way harder to actually scale and maintain. Check out flux architecture.
We’re not just assigning variables directly, current JavaScript frameworks use a compiler.
const [state, setState] = useState(0)
const func = () => {
console.log(state) // 0
setState(40)
console.log(state) // 0
} [foo, setFoo] = useState(1);
[bar, setBar] = useState();
setFoo(10);
setBar(foo * 2); // Is bar 2 or 20 at this point?Let's say you instead did the `setFoo` and `setBar` in a click handler. In that case, when you click the button it would tell React "Hey, in the next render set `foo = 10` and `bar = 2` (since `foo = 1)`. Then React goes ahead and runs your function again, and `foo` and `bar` will both be updated.
The value of `foo` does not change within a render cycle, you literally don't have to worry about state.
It might seem that there’s a chance that people will be confused about what bar is, but in practice all the changes are happening in handlers and bar will be a const anyway so you have no plans to mutate it directly.
Just a follow up. If foo and bar are expected to be constant in the rendering code, what's the point of the setXXX() functions? Why not just make them constant explicitly and say mutating them elsewhere like in the handlers/controllers?
React inverts the MVC paradigm and says "no, you don't get to decide when to render." So if you want to update state, React will manage that for you and queue up the render. With React, your UI and state literally cannot go out of sync (except for refs), and all the data dependencies are managed for you.
Facebook gave a great talk on Flux architecture vs MVC ten years ago that you should check out here: https://www.youtube.com/watch?v=nYkdrAPrdcw
> what's the point of the setXXX() functions? Why not just make them constant explicitly
Look at the code again: it is explicitly constant! `const [myState, setMyState] = useState(0)`. `myState` is a const, and will literally not change its value for the entire render cycle. There is no mutable state to manage, no race conditions. You just tell React what to render based on what the value is now, and React injects the current value for you. The first time, `myState` is 0 since that's the initial value. Every subsequent render, React will give you the latest value. You can pretend everything is constant, because it is.
First of all, I don't believe React component is pure functional with the state hooks embedded inside the component with side effects. Calling UI=F(props) twice with the same props would not produce the same result given the different sets of states embedded in them.
Second, the local variable myState is const but the state is mutable; the variable myState is an alias snapshot of the state. Otherwise what's the purpose of handing out setMyState? setMyState is for mutating the state, right? It seems the need to keep myState constant is due to React's inability to detect changes to the variable to sync up the UI. It uses setXXX() to trigger the UI re-rendering. However, whether setXXX() queuing up re-rendering and causing re-rending loop is inconsequential to the programmers. It's React's implementation detail.
Third, I'm interesting in learning what kind of bugs mutable state would cause in React, so that we can design better systems down the road.
Correct, but you as the component writer don't care. From your perspective, you are writing a purely functional component because you have no control over the injected state. So your function is "pure" with respect to the props that are passed in and the state that is injected by React. It's actually UI = F(props, state)
React can (and will) run your component function multiple times with different values before rendering, so it is extremely important that you have no actual side effects. Otherwise, these "intermediate renders" will affect the final render, which breaks the contract that your function return the same values for the same inputs.
> the local variable myState is const but the state is mutable
It is "mutable" in the sense that it changes between invocations of your function. But no, it is immutable within a single render of your function. The fact that you can treat all state as constant is one of the massive advantages of using React. You literally don't have to think about state mutating within a render cycle. You just write a function that spits out JSX given props and state.
> Third, I'm interesting in learning what kind of bugs mutable state would cause in React
You're going to run into issues where:
* the order that your function is called somehow affects the final render. Now you need to worry about how your function is called, and with what values. Not an issue with React.
* the underlying state is out of sync with the UI, because you changed it but didn't trigger a re-render. Not possible in React (except for refs).
* the internal state of the component ends up in an invalid state because of the ordering of set-state calls and renders. Again, not possible in React because all set-states are batched together and applied consistently to the next render cycle. There's no such thing as a "partial render".
This is like calling the constructor of an OO class a pure function. The class constructor takes in parameters (props) and the created instances don't interfere with each other's states. With all due respect, this stretching of the definition of pure function is beyond recognition.
> * the order that your function is called somehow affects the final render. Now you need to worry about how your function is called, and with what values. Not an issue with React.
The order of the function invocations calling setXX() matters anyway in React or non-React libraries. The queued up setXX() calls pending state updates in React has an order. There's no difference in handling state update ordering between React and others.
> * the underlying state is out of sync with the UI, because you changed it but didn't trigger a re-render. Not possible in React (except for refs).
> * the internal state of the component ends up in an invalid state because of the ordering of set-state calls and renders. Again, not possible in React because all set-states are batched together and applied consistently to the next render cycle. There's no such thing as a "partial render".
Both of these are because React's inability to detect changes to state updates in a comprehensive and fine grained way.
No, because again I must stress that you cannot control the injected state. You merely ask React to set state in the next render. The next call to your function may not have the new state! React can and will call your component function multiple times with different values of state, so you must assume it could be anything. This is why component functions must be written without any side effects, because there is no way for you to know which invocation React will actually persist to the DOM. For this reason, you really are writing a pure function with respect to props and state. It's a requirement in React!
> There's no difference in handling state update ordering between React and others.
The huge difference is that because state is fixed within a render cycle, it is not possible to read an intermediate value. You can't get in a situation where one handler updates a state value, and another (or the same) handler reads that new value within the same render cycle. That's the sort of order-dependent nonsense that can make a component very buggy and fall into an inconsistent state.
> Both of these are because React's inability to detect changes to state updates in a comprehensive and fine grained way.
That's because React is built in a way to provide a set of very specific guarantees when it comes to managing state and rendering it. You are free to come up with "simpler" solutions, but you are going to have to sacrifice some of these guarantees for that simplicity. React component functions have no side effects, and are defined completely declaratively. That is extremely powerful with a lot of advantages, such as being trivially composable. It is extremely easy to extract functionality out of a component and turn it into a reusable hook, because everything is already stateless.
If you ditch all that just so you can use variables, you lose all of those benefits. You'll have to deal with truly stateful components, ones that are path dependent and difficult to reproduce for debugging. By contrast, you can reproduce any React component's UI by passing in the same props and state. This is only possible because state is external to the component and out of your control.
With all due respect,
> For this reason, you really are writing a pure function with respect to props and state.
A pure function by definition is one which returns the same output for the same input. The output (html) of the React functional component with the same props can be different based on the changed state. It is not a pure function. It's really no different from an OO object with internal state.
> There's no difference in handling state update ordering between React and others.
> > it is not possible to read an intermediate value.
There is no intermediate value. All value changes are in the final form as there is no multi-threads reading and mutating the state. The block of code mutating the value is executed fully before another block of code can read it.
As for multiple handlers reading and rendering the state and some might miss the change by another handler, again it's a problem of React's inability to detect change for each handler. If every handler can detect change by any other code (other handlers included), there's no problem.
> That's because React is built in a way to provide a set of very specific guarantees when it comes to managing state and rendering it.
React requires that set of guarantees because its design decision - its use of diff to detect changes. It's a non-issue in other frameworks and solutions.
Yes, and the input includes state. React manages it and sets it before your function runs; your function then reads those values when it calls the hooks, and it is read-only. If I adjusted the React syntax to pass in state as a function argument instead, wouldn't you agree that it is pure? It's the same! Just because it's not passed in via arguments does not mean it is not an input. And a pure function is still pure even if the caller is stateful.
Consider the "rules of hooks" in React: you cannot conditionally use a hook, and hooks must be used in the same order every time. That's exactly the same as regular arguments, making them functionally identical but with better dev ergonomics. That's on purpose: state is an input, but having it passed via function arguments would suck to use.
Question: have you written any React components? This is a basic rule that is one of the first things you learn: components should be pure functions with respect to props and state. They're not even allowed to set state as a side-effect. If you're still convinced it's not pure, can you tell me how a component function's output can change given the same props and state?
> The block of code mutating the value is executed fully before another block of code can read it.
And that's the problem: with arbitrary code, there is no such thing as a distinct "block of code". One function can read value A, set it to B, then call another function, which sees value B, does something as a result, and then it renders. But that's wrong: value B has not been persisted to the DOM yet, so it should not have been read by the second function. Now you're in trouble, because your component is behaving as if both A and B are true at the same time.
This is not possible with React. But to pull that off, they had to externalize state and make it read-only to your component.
This is the same argument that the member variables of an OO object are additional input to its member method and the method is "pure."
> how a component function's output can change given the same props and state?
This is the same argument that given the same values of the member variables of an OO object and the same method arguments to its member method, the method returns the same value.
All these are just twisting the meaning of words and concepts to fit the square React into a functional round hole.
> a basic rule that is one of the first things you learn: components should be pure functions with respect to props and state.
You can certainly mutate the state in a React component; otherwise, what's the purpose of [.., setXX] = useState()? If such a "rule" is so important, why don't React remove the ability?
BTW, the "rules of hooks" are another set of extra burdens. All these rules imposed on the programmers are there due to React's weak design.
> And that's the problem: with arbitrary code, there is no such thing as a distinct "block of code". One function can read value A, set it to B, then call another function, which sees value B, does something as a result, and then it renders. But that's wrong: value B has not been persisted to the DOM yet, so it should not have been read by the second function. Now you're in trouble, because your component is behaving as if both A and B are true at the same time.
If every renderer can detect every single update of a variable/state, the above is a non-issue. Function1 can set v1 to A. The renderer detects the change to v1 and renders it as A. Function2 set v1 to B; the renderer detects it and renders it to B. Function1 and Function2 can be called in any order; the rendering output is consistent with the state. The renderer might be called twice but who cares the eventual outcome is the same (certainly there're memorizing optimization to avoid re-rendering). It's really React's weak design causing all the out-of-sync rendering problems.
So there will be 3 cycles?
1: foo = 1, next(foo = 10)
bar = undef, next(bar = 2)
2: foo = 10
bar = 2, next(bar = 20)
3: foo = 10
bar = 20
Does the above sound right?It just feels a bit weird that there's special .svelte specific rules.
Runes kinda fix this, but it's still a bit weird.
I think Solid or Vue are much simpler (but only did small projects in them) and have a simpler mental model. I've not yet used Preact, but heard good things about it
1. Write some solution with out a UI
2. Decide you want a UI
3. Add React
4. Be forced to re-architect your solution because react wants control of all of your state.
React is supposed to be the V (View) in MVC but it requires full control of the M (model) in MVC and bleeds into the C (controller) as well.
Someone will likely chime in that you can just tell React to re-render the entire UI every frame or write lots of custom functions to monitor your model but that's not really the point. No other UI paradigm requires this.
- design "UI struct" for what you want to display
- Have React fire off events when doing actions
- Those actions get piped into your UI-less solution
- Your UI-less solution updates the "UI struct"
- React updates the parts of the tree that was using part of your struct
if you design this struct in the right way, you can have the updates be _very_ targetted (like, React doing basically no extra work). But your UI struct needs to be really carefully set up so you're not firing things off all over the place.
I think it's still an easier problem than keeping your DOM in sync entirely, but it's unfortunately very easy to accidentally over-render still.
Are you referring to Electron apps or something?
What aspects of Django do you think still stand out compared to Phoenix? It seems like a very solid framework, specially with the recent release of Phoenix LiveView 1.0, which seems like a pretty solid approach to frontend. For context, I’ve worked with Django before but didn’t particularly enjoy the experience—not because of the framework itself (its documentation, ORM, and admin tooling are excellent) but because I’m not a fan of Python, particularly its packaging ecosystem and approach to async, which I find lacking. I haven’t used Phoenix or Elixir before, so I’m curious to hear from someone who has experience with both.
Take ORM for example. You write a model and you get out of the box:
- migrations to create the model and to apply schema changes; - form validation for crud; - admin with permissions to edit it; - helpers to get model by id or throw 404.
Phoenix kinda is in the same market, but you write your migrations yourself, admin panel is a package somebody slapped on top, etc.
It’s not that Phoenix isn’t usable, but getting on that level takes time and effort
It uses a 500-line router and a 500-line UI component lib.