Hacker News new | comments | show | ask | jobs | submit login
Vue.js: the good, the meh, and the ugly (medium.com)
621 points by prostoalex 15 days ago | hide | past | web | favorite | 374 comments



I really like a lot of things about Vue. I was apprehensive about using JSX when I first started using React, and I also did not like setState. I think the real issue, though, was that I wasn't thinking functionally. I now rarely write a stateful component, and when I do, it's usually once, for the entire application, or maybe for a few large subtrees if the app is very large. State kept alive by parameters is extremely powerful and elegant (just read about gen_server in Erlang or the State monad). I am never a fan of two way data binding as an alternative. It's extremely hard to reason about, and it's not nearly as composable or simple as a tree of functional transformations. So I think that, if you compare Vue to React Component classes, Vue can be quite nice, but the reality is that idiomatic React should have you writing 80%+ small, simple, composable functions with no state, and you really can't get any syntactically barer then that. It's also the way I teach React. When you first see a function going from state to jsx, it really just makes so much sense, and you ask yourself why you'd ever bother with anything else.


If plain, idiomatic React so great, why does every semi-complex React app end up bringing in a separate state management framework like Redux or MobX?

The reason is that while you may be able to break up your HTML into a composable hierarchy of purely-functional components, the actual data and state you need to distribute to them has a structure that is completely unrelated to how its laid out in the DOM. In a complex web app, a component nested twenty levels deep may need to display pieces of information, like the user's date of birth and the current temperature on Mars, that none of its parent controls cares about.

At that point, you can either bite the bullet and pass state through layer upon layer of props, completely eliminating any semblance of separation of concerns in your component layering, or inject state into your components via some other mechanism, like Redux/MobX/Context. At which point, JSX is basically just another fancy HTML templating library.

"Idiomatic" React is a fun game to play when doing basic examples, using something like a todo manager, but as soon as you're in the real world, you hit its limitations very quickly.


> If plain, idiomatic React so great, why does every semi-complex React app end up bringing in a separate state management framework like Redux or MobX?

Sadly it seems that's mainly been cargo-culted. It's not the case that React+Redux is the equivalent to say Angular, but by some unfortunate accident due to Facebook's announcement of Flux, and then the hype around Redux as a 'better Flux', people started assuming React+Redux is what is needed to build a React app.

Meanwhile Dan Abramov, Redux creator says [1]:

> Flux/Redux is meant for big apps with complex nested UIs that have many independent parts but share common caches of data.

That's not "every semi-complex React app". In most "semi-complex React apps", most state can be derived from the route (e.g. react-router) or is relatively local. Redux is not required.

[1] https://twitter.com/dan_abramov/status/732719257579065345


There's unfortunately a thin line between cargo-culting and attempting to follow the mainstream.

As developers we can't all be building tools. We choose tools that others build for us, so that we can get our job done. Soemtimes I'm interested in going "one layer down" and build tools, but it's almost always a distraction; we want off-the-shelf products like React and Redux. We need to pick stable tools that promise some sort of longevity. We also need to pick tools where best practices and idioms have been established.

To do this we have to trust someone else's opinion and try to gauge which solutions have the best prospects. This means not just evaluating software based on its own technological merits, but also listening to what "the community"/"the industry" seems to be rallying around; you don't want to be stuck using a library that nobody is maintaining, just as you don't want to be stuck using something that's just badly designed.

When we started using React, there was no state management framework available, and everything was handled somewhat ad-hoc. Then Facebook described Flux, and we realized they were onto something, so we started using their patterns, with some simplifications where theirs seemed overly complicated. Then Redux came along and seemed like a better way to do things.

At each point there was uncertainty about what best practices and "idiomatic" solutions would turn out to be, because the technology was immature. I don't think anyone was cargo-culting. It was just that a lot of people were busy trying to create things, and when there isn't clear guidance, and the alternative is going back to Backbone or jQuery or something, then you just forge ahead, trying to do fit the pieces together.


But if you looked at the official React docs the answer was always 'setState' and embracing components, that was the whole promise of React to begin with. Not once did the React team/docs ever say you needed Flux to build a React app. All of those answers you got were cargo-culted from the community.

Can you really look at where the community is, the perception that still exists that React+Redux is necessary, projects like redux-form (that now admit Redux was a poor fit for forms) and honestly say no cargo-culting happened?

Sympathy for 'attempting to follow the mainstream' though, I understand that. Personally I stuck with Backbone for years longer than most, avoiding the Angular/Ember wars, and the early days of React+Flux til the React ecosystem had matured a little, before jumping over to React at which point it was clearer that Flux/Redux were being misused.


The official docs originally described React as "the V in MVC" [1], so the assumption about needing another layer to handle state and business logic didn't come from nowhere.

The claim isn't that there's no cargo cult around the React ecosystem — but not everyone writing React code is approaching it with experience, which means they try to pick up best practices from other people. That's not "cargo culting"; it's a reasonable thing to do when you have to solve a problem you don't know how to solve!

Ultimately, people aren't being "tricked" into using these tools. They proliferate because they solve real problems people have, and a lot of people would rather work with a popular and well-documented solution (with known advantages and drawbacks) than trying to forge their own path and seeing how it goes.

[1] https://github.com/facebook/react/pull/7012


Can we blame all the bloggers who take upon themselves to explain what the best practices is? Absolutely. There are also projects (like React Forms and React Router) that clearly led down a path of confusion. But it's hard to blame the developers who read those blogs and try to figure out what they should be doing.

I never got the impression, even from the start, that setState() was a good solution, by the way. But it's not like the React authors were completely sure of where the right design was, either. Flux, for example, as it was originally described, appears completely overdesigned at this point. The good design is to be found in Relay and GraphQL.


> Can we blame all the bloggers who take upon themselves to explain what the best practices is?

It's not really about blaming bloggers.

It's really on software team leads and senior engineers to not just follow blog posts blindly. They should be pushing back on bad advice like redux-all-the-things, because to a senior software engineer the tradeoffs of something like Redux should be fairly obvious.

> The good design is to be found in Relay and GraphQL.

Nah again, good example to question what you read/hear.

GraphQL is great from a front-end point of view but complex to implement in the backend, so it really depends on your use-case whether that backend complexity is worthwhile.


Could you provide a source for the maintainers of redux-form admitting that Redux was a poor fit for forms? I'm inclined to agree and am kind of interested to see their reasons.


Yep, sorry I should have included the reference. This post is by the redux-form creator, in which he states why it was a bad idea, and announces its 'spiritual successor': https://codeburst.io/final-form-the-road-to-the-checkered-fl...

> Also, everyone high up in the React community, including both inventors of Redux [1], say that Redux is not the best place to keep form data. Oops.

[1] https://github.com/reactjs/redux/issues/1287#issuecomment-17...


Now, it _does_ depend on your use case.

An isolated login form? Yeah, no point keeping that in Redux - it's not being shared, it's not being persisted, there's no real need to track the history of changes. But, there are certainly situations where you might want to keep some form data in Redux.

As a specific example from my own app: we show some polylines on a 3D globe, and allow the user to edit them. We need to be able to live-update the point locations and labels on the globe as the user edits them, allow resetting edits, and still be able to show the original values elsewhere in the UI. Keeping all that data in Redux makes it easy to do so.

The Redux FAQ has a list of suggested rules of thumb for deciding what state should go in Redux: https://redux.js.org/faq/organizing-state#do-i-have-to-put-a... .


You can achieve all of that with a singleton that is shared and some events (and do some of your own batching). No need for another dependency and you save bloat size.


Well, the whole app is built around Redux in the first place :)


To me this underscores the most unspoken point. Redux is meant for when you specifically want to build your app around redux. It's not meant to tack on some global store to an existing UI. It is UI agnostic way of separating your business logic and side effects from the UI iself (which could be react, vue, angular, whatever)

For the most part, yeah.

Now, the other app my team works on is built with Backbone/Marionette. We've introduced React and Redux to it, and are progressively refactoring over time. It works, although we've got some rather ugly code in several places (some data is in Backbone collections, other data is in Redux, and occasionally some bits of data are mirrored in both places).

I wrote about some of the techniques we're using to integrate them here: https://blog.isquaredsoftware.com/2017/07/react-redux-backbo...


As one of a small group of maintainers of the build tools of our most complex app, I can concur with this. Yesterday I spent 4 hours fixing a single build/parse issue between dev and prod.

I also spent just 1 hour completing multiple RFCs in another app built with create-react-app using redux/connect as a purely syntactic-sugar state propagation layer.

I love the complexity and feeling of fulfillment for triumphing in the former scenario, but it is definitely much more of a distraction than anything else.


I remember when I first started to try and learn React there was only a handful of words and a vague diagram from Facebook about its Flux architecture. And after that there were many, many similar state management libraries. That some in the community picked a smaller one that had in-depth documentation and emphasized stateless / functional style programming is not terribly surprising.

IIRC there were a lot of comments about having to pass props to children constantly (without using a state management library). Seems like it's a lot easier to not use a state management library now that an official, non-experimental Context API exists. But remember, this was only added a few years later.


Agreed. Cargo culting is the main issue. The solution is to try and remain unbiased, and not look for direct synonyms between two very distinct approaches to managing user interfaces.


Well, FWIW js is not the most friendly language for functional programming. I'd argue that the trend toward immutable.js and redux occurred partly because rest/spread syntax was/is relatively confusing, and so immutable patterns without a library feel less elegant until one really groks the somewhat visually opaque semantics of the rest/spread syntax.

Redux also offered a simple approach to the "action bus" idea from Flux, but omitted first class async support, etc. React itself also somewhat overlooked async patterns, which created the idea that their absence was by design and so an additional (opinionated) library was appropriate.

In sum I'd argue that React actually fights against js quite a bit and that it will truly come into its own once reason gets more mindshare.

For those of us who invested heavily in react as all this was becoming clear (and being ironed out) I hope we learned enough to allow better decision making in the future.

Also, React has a few "on by default" performance enhancements that are a bit conceptually confusing and create something of a mismatch with the functional approach.

But still it's difficult (and unpleasant) to imagine the world without React.


Also, MobX is for most devs easier to understand and use than Redux and more similar to Vue and Angular. I think most small react projects should start with no external state management or mobx and only switch if they need it. Unless they already know redux very well and think it suits their project.


Just to add some weight to your opinion about Redux being cargo-culted take a look at this video

https://youtu.be/S6lwJ6Rixnc?t=6m


> the actual data and state you need to distribute to them has a structure that is completely unrelated to how its laid out in the DOM.

It took me many years to realize this. I think very few front end developers understand this. And more problematically: very few framework devs seem to understand it.

Stated another way....

Your tree of UI widgets, and

Your tree of data which feeds those widgets

... are two orthogonal trees.

If you are a front end dev and you haven’t spend time wrestling with that, I strongly recommend it. It’s extremely likely your front end architecture is suffering because of it.

React take the strongest stance on this matter, by making the interface to every widget be one giant shared global. But globals are bad, so while it’s good they acknowledge the situation, they mostly punt on the question of how to deal with it.


>Your tree of UI widgets, and

>Your tree of data which feeds those widgets

Not with a well-designed XML format and XSL-T! But hmm, nobody seems to use that anymore either.


Having done this in the wild a while ago, it seemed to be hard for most of the other developers to do anything complex with it.

You either really got it and then could do wonderful things, or you sorta muddled along with it and it was ok but it was like they were wearing a straitjacket.

I made a pivot table control out of it, with almost all the logic inside the XLST, it was amazingly fast compared to IE6's javascript at the time. I remember that Blizzard used it for the WoW online character viewer which was streets ahead of what anyone else was doing.

Also there's a DailyWTF about someone doing this on a large app, which brought the developer out of the woodwork to defend it who said in fact it wasn't a WTF, it was deliberate, it worked, loads of people loved it. Which prompted a huge debate about how it was actually kinda good, but just too high a learning curve (which is the death knell of many a tech).

Personally I don't miss it. The best way I can sum up XML/XLST up is that it made me feel clever, and now I know that when I start feeling clever about my code that's a sure sign I'm making something that's going to be a nightmare to maintain.


Once upon a time my web site was doing all the rendering via XML/XLST, and I looked forward to what might have been Web Components via the XML Components standards.

Oh well, at least Web Components seem to finally be around the corner, a decade later.


Yes, the lack of reusable controls in hrml is utterly crazy!

> Having done this in the wild a while ago, it seemed to be hard for most of the other developers to do anything complex with it.

Same. Long ago I replaced an expensive Crystal Report solution with reports delivered as XML/XSLTs that used IE's feature at the time of applying the XSLT at the browser. It worked very well and provided nice interactive reports. I also wrote a bunch of cookbooks (for lack of a better term) that allowed the business analysts to create additional reports.


> streets ahead

Pierce? Is that you?


No, I'm from the UK, it's a common idiom over here.


Wouldn’t happen to have a link to that DailyWTF would you? Would love to read the discussion.


I was having trouble earlier, but have tracked it down:

https://thedailywtf.com/articles/Sketchy-Skecherscom

The featured comment at the bottom is from the original devs.

One of the early comments is that it only worked properly on Firefox, which is wrong. IE6+ had excellent, extremely fast XSLT support.

The company I worked for at the time actually had an enterprise app that didn't work properly on FF as it relied on some IE only functionality, some sort of VBScript controls you could embed in IE that I forget the name. They dropped support for them in IE8 or 9. The app was otherwise excellent, basically a sort of dropbox + basecamp for the construction industry before dropbox + basecamp were even made, users loved it. The founding developer was the best developer I have ever known (his quirk was that he'd often forget to rename his functions after prototyping something so a lot of his methods were called Something or Thing or Something2 and we'd have to rename them later to make it clear what they did).

We had a SQL helper that would allow you to write XPath in the SELECT names something like this (I have totally forgotten xpath by now, but hopefully you get the jist):

    SELECT c.CompanyId [@companyId], c.Name [@companyName], 
      o.OrderId [/orders/order/@orderId], o.Name [/orders/order/@name], o.Quantity [/orders/order/quantity]
    FROM Orders o
    JOIN Company c ON o.CompanyId = c.CompanyId
    ORDER BY c.CompanyId
And it would spit out appropriately nested and structured XML like:

    <companies>
      <company companyId="1" name="thing">
        <orders>
          <order orderId="142" orderName="Sally's Order">
            <quantity>1</quantity>
          </order>
          <order orderId="156" orderName="Sally's Other Order">
            <quantity>1</quantity>
          </order>
        </orders>
      </company>
      <company companyId="2" name="different company">
        ..etc
       </company>
    </companies>
     
It was actually pretty nifty, you only got exactly the data you needed for the page, but meant often our business logic was in SQL statements. It did make me realise how infrequently you actually re-use specific data queries and a lot of people over-egg how much data re-use there is or logic sharing that is actually required in a real-world app.

Because you had the XSLT on the page, you could make it dynamic, just post back for the new XML on a drop-down change, button-click, etc.

Another story from there is that they made their own version of jquery just before jquery rose to prominence. It was a nightmare to debug, that fully got me onboard the jquery train.


> It did make me realise how infrequently you actually re-use specific data queries and a lot of people over-egg how much data re-use there is or logic sharing that is actually required in a real-world app.

Agreed. Possibly a microsymptom of the "business only does boring things, developers do interesting things" mindset.

In my experience, one needs to constantly guard against thinking anyone else is mindlessly turning a crank. In fact, they're likely doing just as complex and interesting stuff as you, only with different tools.


Looking at it, xsl:for-each inside of xsl:for-each should be xsl:template with it's own mode.

however it's also really too trivial and really straightforward and boring as a piece of code to be mentioned as a WTF, having difficulty understanding that code would just be a case of not understanding the language, which is also a thing that happens.


I seem to remember that was just a practical thing, sometimes you couldn't be bothered to split it into two.

The context of that article was more that doing XML/XSLT at all was a WTF.


IIRC, Colloquy (a macOS IRC client) used to do this. Each IRC channel was basically an XML feed, and the theming was just XSLT applied to the XML feed and the output displayed in a WebView widget.


I think this is the issue Relay tries to solve. It basically just allows components to declare which part of the data tree they are concerned about without having to have knowledge about the data that other components need.


You wrote "React take the strongest stance" but you meant redux right?


No, React has a notion of a single giant state object, right?

No. Vanilla React just give you the option to store state of any size in any component.

So I see where you're coming from. To first address Redux, etc, React has no opinion on state storage, it's a feature not a bug. Obviously you need to store state somewhere, and Redux, Relay, etc are just tools to address that concern. But that's really unrelated to what you're trying to address, which is coupling between leaves that have shallow common ancestors, but are themselves quite deep. Although in my experience a good website does group related pieces of information, and so well organized state often maps easily to a well organized UI, functional programming gives us the tools to avoid deeply nested expressions regardless of your application (or even your framework).

One thing to realize is that you always get to decide on the granularity of your compositions. It is not necessary to build a deep hierarchy if you design the granularity of your interfaces correctly. Another great tool is higher order functional programming, such as passing components to components (via children). In this way, it is easy to describe generic interfaces and supply specific pieces of data without having the intermediary interfaces know or care about that data. Another approach, akin to using something like the state monad, is to use Reacts context feature, but this is rarely needed, in my experience.

Personally I make heavy use of higher order components, and I find I rarely exceed a component tree height of three.


As someone one who rewrote a React/Redux project with bare React : Everything in your post is true, I made the same observations and I reached the same conclusions.

Right now with a few devs it is going very well but I do worry about on-boarding people who are not proficient in functional programming.

React code without a global state management library is very pleasant and easy to read/understand for many, but for some it is not always obvious to write. You may have to spend more time code reviewing and training newcomers who will sometimes feel like their task is impossible without Redux. I have yet to see if those requirements can still hold for a big team but I think it is possible.

My current opinion on Redux is that it is best suited for existing project migrating to React because you may inherit very odd relationships between the view and the data and Redux will avoid you a lot of pain on this regard. A new project should avoid Redux & co as long as it can.


> Personally I make heavy use of higher order components, and I find I rarely exceed a component tree height of three.

That's my experience as well. If you use a deep component hierarchy you have bigger problems than those solved by Redux, VueX or the Context API.

Higher order components or even simple functional components are really underrated when it comes to making your application simpler to reason about and to maintain.


Is there a blog post explaining higher order components in more detail, preferably with examples?


Higher Order Components are like Aspect Oriented Programming - it takes a component and adds some stuff to it. It can add that stuff to any kind of component. That's all you really need to know.

Examples of HOC are the connect() call from Redux, or the withNavigation() from React Navigation, or injectIntl() from React-Intl. These respectively add Redux functionality, navigation functionality, and internationalization functionality to your component.

I think the name "Higher Order Component", like many things in the React world, is poorly chosen and actually obscures what it is, how it works, and makes it look more intimidating than it really is. It's technically correct (like 'reducer' is), but communicates nothing.


I agree.

It's effectively a replacement for the old React mixin system.

It happens to use functional programming methods, but that's an implementation detail.


Yep, lots! See the "React Component Composition" section of my React/Redux links list: https://github.com/markerikson/react-redux-links/blob/master...


The doc is very detailed with good examples : https://reactjs.org/docs/higher-order-components.html


React was advertised from the start as the V in MV-whatever, so that seems like an overly restrictive definition of "idiomatic".

> At which point, JSX is basically just another fancy HTML templating library.

JSX is optional syntax sugar; my team uses React and Redux heavily, but we've opted not to use it.

HTML templating is great actually, all the rendering is data -> UI.

If you go back to the early Rethinking Best Practices presentation[0], it boils down to asking why client side development isn't like like HTML templating. The answer is that updating the entire page DOM on every change is unworkable, there needs to be support for partial updates. That's what React offers, a return to the data -> UI paradigm, without having to write a secondary code path for partial updates.

[0] https://www.youtube.com/watch?v=x7cQ3mrcKaY


Out of curiosity, what are you using instead of JSX? Plain `React.createElement()` calls, `createElement` aliased to a shorter variable like `e`, or something like the `react-hyperscript-helpers` library?


We’re still using https://www.npmjs.com/package/react-dom-factories for plain DOM elements, so code looks like

    dom.div({ props }, ...)
For our own components, we export the output of React.createFactory https://reactjs.org/docs/react-api.html#createfactory rather that the component itself, so rendering code looks like:

    MyComponent({ props }, ...)
I realise that both of those are marked legacy, with a nudge towards using JSX instead, but they are pretty thin wrappers around createElement so it seems like a small dependency.


it's funny how originally jsx is what kept me away from react, and now it's what keeps me from leaving.


It's funny how everybody hated E4X when Adobe and Mozilla were doing it, and love JSX now.


I didn't even know this existed.


You can actually leave react and still keep JSX. This tiny library lets you use JSX as a templating mechanism: https://github.com/wisercoder/uibuilder


For me (Vue + Vuex) the choice was simple: you get undo for free.

Having a shared store really does change the way you look at web apps - it's almost a completely different paradigm. If you can avoid re-loading the data for a view if you already have it then then opening a new view to edit a subset of the data instead of dealing with popup makes life so much easier - you get a lot more freedom with the UX and going back to the previous view with the parent data is almost zero-cost.


You can have undo for free using React as well. React doesn't care about how you manage your state changes, and it will selectively render only the parts of your app that changed.


Not to mention, I believe time travel is an officially supported functionality for redux, if you choose to use that.


But now you have a new problem: Managing the freshness of that cache.


Actually that's my favorite thing about the Redux model.

The vast majority of our codebase is comprised of simple idiomatic React components. Our reducers and glue code (e.g. @connected containers) are a very small portion of the codebase. If I woke up tomorrow and decided Redux was the source of all our problems I could completely remove it while only needing to refactor a small portion (<5%) of our codebase that's mostly boilerplate anyways.


Idiomatic React is both compatible with and orthogonal to state management libraries like Redux or MobX. React is (in my opinion, and likely in the opinion of its creators and maintainers), a library for creating reusable ("dumb" or "presentational") components. In many web apps built with React components, you will want another library to manage the global state of the entire application and provide your dumb components with read/write access to specific pieces of that global state.

I don't understand your point that injecting state into your components (e.g. with Redux' connect function) means JSX is just another fancy HTML templating library. All you need to do is have your React component export a "dumb" version as well as a connected version. Your dumb version will still be reusable in other parts of your application, and any other application could also use your dumb component and connect it to their global state through whatever means they please.


I've felt the same way. Vuex, Redux, MobX, or other application state libraries, all help in the event when passing data down through components that don't care about the data they are passing along becomes tedious. I like the general idea of "data down, actions up", but when it comes to separation of concerns, what is the point of a component taking parameters that it is just going to pass to a subcomponent? When components don't use the parameters in a meaningful way, the parameters are just noise. I came to this realization after passing the same parameters down about seven levels deep through components to question the mantra. I try to avoid shared and global state, but there are times that it just becomes very useful. It is important to now and again question if the dogmatic approach is pragmatic.


> seven levels deep

There's your problem I think, as other sibling comments pointed out.


React isn't about JSX and passing foo/onUpdateFoo down 20 levels of props. It's about data flowing in one direction down a tree of diffable virtual components, then being passed back up. The single most important idiom is that all data for a component should come from state or props, and that when you need to break this rule you should do it inside a single component or a handful of components that will then handle your global state management.

I understand that such an open-ended product is frustrating to use because redux is insanely overengineered, mobx reintroduces data binding, and context is buggy and terrible, but I don't think what you're calling "idiomatic React" is actually considered idiomatic by anyone, including the core development team.


Redux is not over-engineered. It's a simple library that's <1000 lines of code. It is great for large, complex apps where state gets hairy to manage. It's a bit verbose for smaller apps. But just because something is verbose does not mean it's over-engineered. It is explicit in defining all the possible states your application can get in. That's useful for a certain class of application.


It might have been more accurate for me to have said "the code you will get if you follow the reference implementations and documentation of Redux will be overengineered". I dislike three things: that dispatch isn't usually made globally available, but is passed through context, which makes it effectively global anyway; that asynchronous actions are only available via plugins despite being a core part of JS development; and that dispatching an action is just a more complicated way of calling a function.

Interested in hearing what you think, though. My Redux experience has been more limited by trying to avoid it on small projects.


Hi, I'm a Redux maintainer, and I'd like to clarify a few things.

First, your points about `dispatch` and `context` are specifically about the React-Redux bindings, not the Redux core itself. React-Redux is specifically intended to act as an abstraction layer so that your own components are "unaware" of Redux, which keeps them more reusable and more testable. It also saves you from needing to write store subscription handling every time you want to make use of data from the store. My "Redux Fundamentals" workshop slides [0] show examples of what it would look like to hand-write store subscription code all throughout your UI, and it would be a pain.

If you _really_ want to, there's nothing stopping you from importing the store globally across your application and using it, but that misses out on the benefits of React-Redux, and also ties you to that one specific store instance.

Second, you can absolutely do async logic without any middleware. However, one of the key design points of Redux was to allow users to choose which approach they want to use to handle async logic, without limiting users to whatever was built in to the core. I discussed this in my "Redux Ecosystem" talk at ReactBoston last year [1].

You can certainly do async logic without any special middleware - just `connect()(MyComponent)`, throw in a `setTimeout`, and call `this.props.dispatch()`. The point of `redux-thunk`, the most common async middleware, is that it provides a generic way to move async logic outside of your UI and make it reusable [2].

Finally, the "dispatching an action === calling a function" comparison can be true, but only if you're using Redux with a limited mental approach and treating actions like "setters". If you start thinking about actions as more of an "event that occurred", then that leads to having multiple parts of your reducer logic independently respond to the same action and update their own pieces of state (which is an encouraged usage pattern). Justin Falcone had some good thoughts on this a while back [3], and I talked about this some in a fewmore of my blog posts [4] [5] [6].

[0] https://blog.isquaredsoftware.com/2018/06/redux-fundamentals...

[1] https://blog.isquaredsoftware.com/2017/09/presentation-might...

[2] https://blog.isquaredsoftware.com/presentations/workshops/re...

[3] https://medium.freecodecamp.org/whats-so-great-about-redux-a...

[4] https://blog.isquaredsoftware.com/2017/01/idiomatic-redux-th...

[5] https://blog.isquaredsoftware.com/2017/05/idiomatic-redux-ta...

[6] https://blog.isquaredsoftware.com/2017/01/practical-redux-pa...


This is all absolutely true! Redux and React-Redux, and their associated documentation make a lot of intelligent design tradeoffs that have a lot of thought put into them, and that's worthy of respect. "Overengineered" was too strong a term, and I shouldn't have used it. Sorry.

However, some of the things that have been traded are default configuration that represents typical use, standardisation across the ecosystem, and brevity. I think that for a lot of use cases, these tradeoffs make React-Redux harder to use, and that as a whole they make it easier to cause significant architectural problems for a newer or less technical user.

> If you _really_ want to, there's nothing stopping you from importing the store globally

What I've taken to doing is exporting a dispatch function that calls the store's dispatch, not the store. I think this better captures the intention behind Flux than a higher-order component, without much cost, since dynamically swapping between stores doesn't seem common.

> ...one of the key design points of Redux was to allow users to choose which approach they want to use to handle async logic...

This power and choice, while allowing a lot of freedom, comes at the cost of a fragmented ecosystem. The Redux documentation page for async actions lists six different packages that can help.

> the "dispatching an action === calling a function" comparison can be true, but only if you're using Redux with a limited mental approach and treating actions like "setters"

I may not have explained that very well. Actions themselves make perfect sense from the perspective of a reducer, and clearly they must be dispatched, but they're a state management detail that the UI doesn't need to know about. Something similar to redux-action could be the default.

I suppose my core problem with Redux/React-Redux is that I don't understand why a typical component in a typical app doesn't look like

  import { connect } from 'redux'
  import { deleteFoo } from '../actions'
  
  const FooList = ({ foos }) => {
    return foos.map(foo => <button onClick={() => deleteFoo(foo.id)}>Delete {foo.name}</button>)
  }
  
  export default connect(state => ({ foos: state.foos }))(FooList)


Yeah, for a while it seemed like there was a new Redux side effects lib coming out every week. At this point, though, it's pretty much standardized on thunks for basic use cases, and either sagas or observables for more advanced use cases based on your preference of writing async logic.

> What I've taken to doing is exporting a dispatch function that calls the store's dispatch, not the store.

Not sure I follow that train of thought - could you point to an example?

> Actions themselves make perfect sense from the perspective of a reducer, and clearly they must be dispatched, but they're a state management detail that the UI doesn't need to know about. Something similar to redux-action could be the default.

This is why we recommend use of action creators, so that a component is just calling `this.props.doSomething()` without it "knowing" that a Redux action is actually being dispatched.

Per your snippet there at the end:

- `redux` and `react-redux` are deliberately separate packages, because the Redux core is 100% vanilla JS, and independent from React (in the same way that `react` and `react-dom` are separate packages - the core React logic is independent of the platform-specific reconcilers). So, `import {connect} from "redux"` wouldn't be appropriate.

- The use of `deleteFoo()` that way assumes that it's pre-bound to a specific store instance, which limits the reusability of your logic, and also makes it a lot harder to test. `connect` abstracts away the question of "which store instance am I interacting with?", so that your components and logic are more testable and reusable.

> Something similar to redux-action could be the default.

For what it's worth, earlier this year I threw together a small `redux-starter-kit` package: https://github.com/markerikson/redux-starter-kit . The goal behind it is to simplify some of the most common pain points around Redux: store setup (including thunks and devtools), writing immutable updates in reducers, and having to install multiple packages out of the box. The biggest thing I know it's still missing at this point is indeed something akin to `redux-actions` - see my notes at https://github.com/markerikson/redux-starter-kit/issues/17 .

I haven't had time to push it forward further, but I would seriously like to get some more eyes on it, see if there's any other use cases we should be covering, and then make it an official Redux-branded package and update our docs to recommend that people use it.


> Not sure I follow that train of thought - could you point to an example?

Something like

  const store = createStore(...)
  export const dispatch = (action) => store.dispatch(action)
It removes the temptation to read directly from the store.

> `redux` and `react-redux` are deliberately separate packages

Yeah, my bad, got the import wrong.

> ...limits the reusability of your logic...

When would this become a problem, in practice? Reusable actions across different react/react-native UI, or multiple apps? Switching between user accounts? How common a use case is it?

Even if this is a constraint, I'm of two minds about whether a hack in isolation is worse than more complicated action boilerplate in general.

> ...and also makes it a lot harder to test...

This can be mitigated by Jest's mocks.

> https://github.com/markerikson/redux-starter-kit

That's really good. Unfortunately, it's not the same thing as bundling it with Redux proper.

Anyway, thanks for engaging with me. I never intended to do a deep dive into Redux's design, only to sympathise with stupidcar's comments about third-party state management, but it's interesting to hear the perspective of a maintainer.


Sure. I'll toss in a few more thoughts here in response.

Your `dispatch` snippet could be simplified to just `const {dispatch} = store`, because the store isn't a class instance - it's a closure. However, I'm not sure why you'd feel a need to "remove the temptation to read directly from the store". In what scenario are you trying to dispatch actions (presumably from the UI), but not read any data?

A basic example of reusability is the unit testing scenario itself. Ideally, you want to minimize the amount of other app code that's getting pulled in, so you can test this one piece in isolation. A React component shouldn't "know" about a store at all - it should just be getting data and functions as props. Similarly, even async logic _should_ be testable in reasonable isolation. If you are directly importing a singleton store instance throughout the entire app, you're coupling all of your logic to that one instance.

Typical testing of store-related logic involves the `redux-mock-store` package, which is just similar enough to a real store to let code run, but records which actions have been dispatched. Similarly, if you do want to test a Redux-connected component and its pieces all together, you would normally provide a unique store or mock store instance there in the unit test - you don't want to drag in the rest of your codebase to test that one piece. (And sure, Jest has some pretty good mocking abilities, but not everyone's using Jest.) I've got some slides on standard Redux unit testing practices [0], and a large section on testing in my React/Redux links list [1].

Outside of testing, yes, reuse of React+Redux across multiple platforms is viable, as is sharing code in libraries. But, again, that only works if the store is effectively dependency-injected at runtime, and that's the point of how things like `connect()`, thunks, and sagas are set up.

I agree that a separate "starter" package isn't the same as putting that all in the core, but that's kind of the point. The starter kit depends on several other packages (`redux-thunk`, `immer`, `selectorator`, etc), while the core Redux library is tiny and standalone. The intent has always been to keep the core small, and let people build pieces on top of it. So, for this package, the specific goal is to help simplify the most common use cases and concerns I've seen, while still avoiding dictating the rest of their app design.

[0] https://blog.isquaredsoftware.com/presentations/workshops/re...

[1] https://github.com/markerikson/react-redux-links/blob/master...


State management seems like inherently a different problem to solve than the problem React solves. What front-end framework out there has a single state management pattern that works for all sizes?

It’s easy to point out frustrating things or hard problems; it’s not easy to point to a way out.

Personally I love the explicit state flow react forces, and I would hate to move to a framework where I spend time figuring out how data goes from point A to point B.


People mainly use Redux because they don't understand that React isn't Angular. React is meant to care only about UI state. Your application state should be kept separately, and React should just be a function from app state to UI.

Redux is what you get when people try to use React as a "full-app" framework instead of what it's meant to be: a view layer.


> Your application state should be kept separately,

Is Redux not exactly that?


It can be used for that, but it quickly becomes cumbersome. Redux, in my opinion, should be used for complex UI state in applications with complex interfaces where interactions with one part of the UI can change very different parts ("spooky action at a distance", so to say). But it shouldn't be used to keep all your application's state.

Your application's state should live outside of React, and be passed in as the root's props.


I agree w.r.t. what you should Redux for. That said, if you store application state in Redux, is that nout "outside of React", passing it in as props? (Though not necessarily the root's props.)


I think the opposite.

Redux should have your application state, and any UI state should be in pure React (portals, context, etc).

Redux -> app data React -> UI


> People mainly use Redux because they don't understand that React isn't Angular

Ironically, Redux came out around the time Angular popped. While not everyone, a significant portion of early adopters came in because they were rejecting the Angular 1.X way of handling state, and Redux was the polar opposite.


So how do you manage your application state? I‘m curious, because a search for such a phrase always brings up Redux, Thunks and Saga.


You keep it out of React, manage it however you want to and is most convenient for your application's data model, and pass in the parts that are relevant to UI as props to React's root.


You can make any suitable variation of the following pattern.

You build a DataSource class/prototype with methods such as :

- fetch

- addChangeListener

- removeChangeListener

You extend this class for each data type :

  class CommentsData extends DataSource {
    // Your custom data source with your data treatment and data getters
  }
And you use the Higher-Order Component pattern: https://reactjs.org/docs/higher-order-components.html


That's just a more Object Oriented Redux (or less, if we consider OOP is originally message passing), and probably without all the connect optimizations.

I'm not a fan of Redux either, but I fail to see what problems this approach solves.


> That's just a more Object Oriented Redux

> I fail to see what problems this approach solves.

You are absolutely right I gave an ad-hoc Redux as an example of Higher-Order Component.

Being OOP or not is only a matter of implementation of your data source. Here you have absolute control on it and depending on the type of your data, the frequency at which it is updated or its (a)synchronicity, you may prefer/need something very different from a dispatcher/action/reducer system.

The real pattern here is the HCO and yes Redux also use this pattern to build "smart components" with "dumb" ones. But it does it in a very opinionated way.

As an example : for performance reasons you really don't want Redux to handle real-time data with very frequent updates, it is better to manage this kind of data your own way.

A more common case is having only a few amount of data that have to be shared across the tree (things like an user session or the chosen language). If your component tree has too many level of depth an ad-hoc solution can do fine here.

IMHO there is two type of arguments for why Redux might not be needed :

1) A reasonable UI respects separation of concerns.

There should be limited need for data exchanges or interactions between two unrelated components. Making the data flow from the local state of a "smart component" is fine most of the time.

2) What Redux does can be done with less boilerplate when and where it is needed.

You can make your component "smart" in a lot of ways. It can be done with pure React state management, it can be done with custom data sources and HCO, it can be done with JavaScript CustomEvents and so on.

The worst problem here is that because Redux is a (very good) opinionated abstraction, lots of developers forget it is a library and not a framework so they try to find what they think is the most Redux-way of doing things. I've seen tons of projects that ended up being a mess of Redux/Thunk/Reselect plus whatever middlewares where updating a single property implies at least handling it in the reducer, adding a selector, and adding the result in mapStateToProps. Redux is definitely not a bad solution but in becoming a standard one it hurt a lot of projects.

This situation is very well explained by pcstl above when he says

> People mainly use Redux because they don't understand that React isn't Angular.

> Redux is what you get when people try to use React as a "full-app" framework instead of what it's meant to be: a view layer.


What connect optimizations? Redux is quite slow.


`connect` does a _lot_ of work to ensure that your own components only re-render when necessary:

- It checks to see if the root Redux state is different than last time, and bails out if it's the same reference under the assumption that nothing changed

- It checks to see if the return values from your `mapState` function are shallow-equality different than last time, and again bails out if they're the same

- The handling for `mapState` and `mapDispatch` is heavily memoized to cut down on unneeded work.

If you have specific performance concerns with a Redux app, please let me know - I'd be happy to offer advice and point you to possible solutions. But, a blanket statement that "Redux is quite slow" is meaningless without context for what's happening.


In large apps mapStateToProps gets called when things my component doesn't care about change - its a simple downside to having one global store as a design.

We now speed things up buy removing redux and just using events with multiple stores anyone can access - we can easily tune the system and don't have to rely on magic that can never be as efficient. Plus the syntax is much cleaner.


Dispatch is another big culprit.

I have exactly the same experience and implemented the same solution. An ex-colleague also did the same thing. We both worked on collaborative webapps but in different companies at the time so performance gain was very important.

I still use Redux on some projects but I definitely start the new ones without thinking about it.


> Dispatch is another big culprit.

Could you clarify what you mean by that?

Per both of your comments: generally speaking, your `mapState` functions _should_ run as quickly as possible. Ideally, a `mapState` function should just grab a couple values from the Redux state object and return those.

If a component needs the store data to be transformed in some way, we recommend using memoized selector functions [0] to cut down on unnecessary work.

So, in a well-written app, your `mapState` functions shouldn't be bottlenecks.

As I said, if you've got some examples of specific perf issues, I'd be happy to offer advice.

[0] https://blog.isquaredsoftware.com/2017/12/idiomatic-redux-us...


> Could you clarify what you mean by that?

A call to dispatch is significantly more expensive than the update of a JS object

> Ideally, a `mapState` function should just grab a couple values from the Redux state object and return those.

Ideally it should, but in practice it is really much more expensive than getting a value in a JS object

> If a component needs the store data to be transformed in some way, we recommend using memoized selector functions [0] to cut down on unnecessary work.

I used Reselect before removing Redux. Beyond the fact that it adds a lot of boilerplate it does not help if you do need a lot of data updates.

> So, in a well-written app, your `mapState` functions shouldn't be bottlenecks.

It shouldn't but a few dozen of updates per second through Redux on a mobile take a toll on its performance serious enough to not be able to keep 60fps in a WebGL context.

I decided to remove Redux after noticing the performance overhead per function call in the Chrome performance profiler, so I know that in practice "dispatch" and "mapState" are not comparable to just editing or grabbing "a couple values from the Redux state"

My ex-coworker had the same issues because he needed to display a lot of items handled collaboratively with smartphones. In both of our cases we have a high rate of data updates, even if we optimize like crazy we are never going to fall under 4-5 update/second per connected user.

So yeah Redux can run well for webapps with a slow/regular pace of update but for more performance sensitive apps you do pay a Redux performance tax.

Again I still use Redux on some projects and I like it but the limits are there. So now I don't hesitate to do without it first and to use it when I need its abstraction.


Hmm. Could you maybe file an issue on the React-Redux repo and provide some repro examples for your use case? I'd be interested in seeing the perf traces myself. This would also be valuable as we work on refactoring React-Redux to work with the new React context API. I have a hunch that my proposed architecture will improve perf, but having more benchmarks would be helpful.


You really are helpful and you try to fix this so I really want to say yes but I am currently grinding for my own startup so I know that a lot of time will pass before I actually do it so I don't promise anything.

A good way to test it would be to make a simple websocket server that simulate n users each sending n' fake xyz position and rotation data per second. This data updates a Redux store in a React app made with Aframe (HTML wrapper around ThreeJS). You make n cubes move and rotate along the data in the store. Compare the fps you get against the fps you get with a vanilla solution. Also check what happens on the performance tab of chrome

I am able to recognize that my use case is very specific. I used React/Redux/Reselect and Aframe/ThreeJS with sockets a year ago. Now I kept React but the rest of the stack have changed for nearly a year


Gotcha. I've made a note of this in https://github.com/reactjs/react-redux/pull/898 for future reference.

If you ever do have some free time to throw together an example app that demonstrates this behavior, please feel free to link it in that issue, or ping me directly (Twitter and Reactiflux are usually best).


I ended up hacking a benchmark. I couldn't beat that itch !

I mentioned it in the pull request, here it is : https://github.com/Kalkut/redux-data-frequency-benchmark


The problem is that they run too often, not that they are slow. mapStateToProps is called too often, and that leads to a bunch of needless shallow compares and often renders. Its a weakness of the magic design, and if I need to optimize the magic might as well just implement the whole thing.


> as soon as you're in the real world, you hit its limitations very quickly.

Isn't a good chunk of AirBnB, Facebook, Instagram, Netflix, The New York Times and Dropbox written in React?

The built-in state management has limitations, of course. I see it best for keeping state relevant to display-- React is supposed to be a "view" library, not a state management one.


Is there a way to tell or are we going by what these companies disclose?


Use the react devtools when looking at those websites.


And also Office 356


Both Airbnb and O365 web apps are horribly slow in the browser and hasn't had any noticeable feature growth in the past 4 years so i wouldn't use these as good examples of neither performance nor productivity.

> If plain, idiomatic React so great, why does every semi-complex React app end up bringing in a separate state management framework like Redux or MobX?

Because React = state to DOM while Redux = how to get from previous state + action to a next state? :)

They do different things.


Because async state management is a pain, and hard to reason about, that is what Redux and MobX are for.


if walking is so great, why does every semi-long distance end up requiring a car or bicycle?


It saddens me that JSX became so popular in the React community. I find the syntax verbose and hard to read ... similar to HTML.

At my last company we used `react-hyperscript` which was a simple wrapper around `react.createElement`.

Ultimately, the React developers made the mistake of making `createElement` so annoying to work with, I assume because they bought into JSX. Granted, JSX might have been necessary when React was first created in order to ease people into transitioning to HTML in JS, but I feel like we can move passed that now.

I highly recommend `react-hyperscript`: https://github.com/mlmorg/react-hyperscript


If you care about compile-time checking (you would, if you work on medium to large applications) then JSX (or the TypeScript variant, TSX) is much better because it catches invalid or mistyped attribute names etc.


Looking at the sample in the usage section, I don't see why you could not just write a declaration file that would catch wrong attributes and so on.


Only because it is more mature. No reason you can't write a linter for hyperscript.


Agreed. Personally, I much prefer ClojureScript's approach to react, which is to use native vectors combined with keywords. So a component could be declared like this example from the re-frame framework. [:div.garbage-bin :on-click #(re-frame.core/dispatch [:delete-item item-id])] Easier to read, no need for an extra compile step or any non-native syntax.


about 30 seconds after learning react, I wrote a parenscript wrapper for it because I find the SGML syntax to be super annoying.

A translation from the JSX example that was the first (only?) example on the React homepage at the time:

https://github.com/jasom/parenscriptx/blob/master/example/co...


Last times I used hyperscript I just got lost in the sea of parens, brackets, and braces. Never had a problem with cl-who though, so don't really know what that's about.


You don't need JSX to work with React. JSX is a paper-thin DSL on top of `React.createElement`. Use that, if you want.


excuse me if i'm wrong, but isn't it just a snippet for react.createElement?


react-hyperscript seems to also parse class names ('div.example'), ids ('h1#heading') and come with other goodies. Looks pretty interesting, and I appreciate they doing away with the need of a pre-processor ¯\_(ツ)_/¯


I looked through the code and it's about 40 lines long. I don't mind of people using small libraries like this, but it's a bit fun to see it presented as some kind of revelation :)


How is html hard to read?


Also Vue is multiple languages. There's a pseudo-HTML language. There's a loop language inside v-for, a special assignment language.

React is just JavaScript and HTML.


The amount of special cases in Vue templating syntax is comparable to the special cases and gotchas of JSX. It's not much, really.

I personally find Vue templating syntax much easier to follow than JSX, but that's because I'm used to it. I honestly believe that's how React users feel about JSX too.


> The amount of special cases in Vue templating syntax is comparable to the special cases and gotchas of JSX

This is patently not so.

Vue has:

- three different html-like attributes

- three different scripting languages in templates (two Javascript-like, one Javascript, but only expressions)

- one scripting language for controller/model which actually breaks JS assumptions (about what `this` is, for example) by magiacally hoisting some (but not all) properties of an object

https://pbs.twimg.com/media/DbVEoKOX0AEEen6.jpg:large


    This is patently not so.
Maybe if you are used to JSX.

    - three different html-like attributes
: and @ are just shorthand for v-bind and v-on attributes.

v-bind and v-on (and v-if) accept regular javascript, and it's not just expressions... you can use `active = true` to change a data value, for instance.

The only exception is v-for, as you mentioned, but it is close enough to ES6 for syntax to make sense, at least IMO.

    - three different scripting languages in templates (two Javascript-like, one Javascript, but only expressions)
This is splitting hairs a bit, isn't it? Apart from v-for, you can write pretty much anything you want in the other two.

    - one scripting language for controller/model which actually breaks JS assumptions (about what `this` is, for example) by magiacally hoisting some (but not all) properties of an object
You mean the script part of components? Do you have any examples of that?


> just shorthand

> accept regular javascript... The only exception is... but it is close enough to ES6

So you basically validated all I've said. And it's also incomplete. Because the amount of gotchas and things that you have to constantly keep in mind in Vue is mind-boggling compared to JSX. Because JSX is a paper-thin wrapper on top of React.createComponent, and goes out of its way to keep everything in Javascript. Unlike Vue.

Lets see your defence:

- : and @ as shorthands

It means new syntax that you have to learn, and know differences between. For all intents and purposes Vue has three different types html-like attributes. JSX has only one: javascript names.

- v-bind etc. accepting regular Javascript

Let's see how this is false:

    <label @click="edit(todo)">
This is not Javascript. If it was, it would assign the result of the function call to @click. It doesn't. It's a Javascript-like scripting language that has magical binding into regular Javascript.

- exception is v-for, as you mentioned, but it is close enough to ES6 for syntax to make sense

So, it's not Javascript (unlike some other places where it is Javascript), and it's not ES6 syntax, but it's "close enough to ES6". So it's not. It's a different Javascript-like scripting language.

The only place where Vue allows regular unadulterated Javascript is inside curly braces: {{}}. And there it only allows expressions (Note: JSX also only allows expressions inside curly braces).

However. Even there it's not Javascript. Not really:

    {{ record.commit.message | truncate }}
Valid Vue. Invalid Javascript.

- You mean the script part of components? Do you have any examples of that?

Of course. See inline comments. Example from here: https://vuejs.org/v2/examples/tree-view.html

    Vue.component('item', {
      template: '#item-template',
      props: {
        model: Object
      },
      data: function () {
        return {
          open: false
        }
      },
      computed: {
        isFolder: function () {
          // `this.model` magically hoisted into `this`
          // from `object.props.model`
          return this.model.children &&
            this.model.children.length
        }
      },
      methods: {
        toggle: function () {
          // `this.isFolder` magically hoisted into `this` from
          // `object.computed.isFolder`
          if (this.isFolder) {
            // `this.open` magically hoisted into `this` from
            // `object.data` which is a function that 
            // returns an object whose keys and values are hoisted 
            // into `this`
            this.open = !this.open
          }
        },
        changeType: function () {
          if (!this.isFolder) {
            // this.open can be set directly. Magic
            // this.model.children cannot. Not magic
            Vue.set(this.model, 'children', [])

            // `this.addChild` magically hoisted into `this` from
            // `object.methods.addChild`
            this.addChild()
            this.open = true
          }
        },
        addChild: function () {
          this.model.children.push({
            name: 'new stuff'
          })
        }
      }
    })


Just wanted to add to your argument an inverse argument (for JSX, instead of against Vue):

JSX is actually just JavaScript with this one special rule:

    <foo bar={baz}>child1 {child2}</foo>
becomes

    transform("foo", { bar: baz, children: ["child1 ", child2] })
That's it. All the rules of JSX can be inferred from that one transformation.


> Let's see how this is false:

    <label @click="edit(todo)">
> This is not Javascript. If it was, it would assign the result of the function call to @click. It doesn't. It's a Javascript-like scripting language that has magical binding into regular Javascript.

You're wrong. The contents of the event handler is JS, the whole snippet is obviously HTML.

    <button onclick="alert('Hi')">Say Hi.</button>
This is also plain regular HTML and has been since HTML4 (1997). The value of the onclick attribute is a string of JS. There's no assignment of the result happening. It registers a click handler. The only difference between the two, on a surface level, is that the Vue example has things in scope (edit and todo) that aren't globals.

I love it how you chose just one of so many things listed. And how you got it so wrong:

> This is also plain regular HTML and has been since HTML4 (1997).

What below is plain regular HTML? Taken from here: https://vuejs.org/v2/examples/tree-view.html

    <div
      :class="{bold: isFolder}"   <--- binding to JS-like objects doesn't exist in HTML
      @click="toggle"             <--- If it was HTML it would've been toggle()
      @dblclick="changeType">     <--- If it was HTML it would've been changeType()
      {{ model.name }}            <--- etc
      <span v-if="isFolder">[{{ open ? '-' : '+' }}]</span>
    </div>

Oh. Ooops. None of it. It's a custom HTML-like DSL with three types of magic attributes (magically bound to some Javasdcript code) with three different scripting languages in it.

For reference: https://developer.mozilla.org/en-US/docs/Web/Guide/Events/Ev... etc.

Edit

Let's add more "plain old HTML". Plain old HTML v-ifs that accept JS booleans. Ah, plain old HTML v-fors that accept a ES6-like (but not truly ES6) mini-DSL. And other plain old HTML attributes.

    <ul v-show="open" v-if="isFolder">
      <item
        class="item"
        v-for="(model, index) in model.children"
        :key="index"
        :model="model">
      </item>
      <li class="add" @click="addChild">+</li>
    </ul>

Have you ever made a graphql server with apollo-tools? Do you complain that SDL is a "new syntax" that you have to learn when you can just use regular javascript?

> <label @click="edit(todo)"> > This is not Javascript. If it was, it would assign the result of the function call to @click. It doesn't. It's a Javascript-like scripting language that has magical binding into regular Javascript.

Great, so it's not javascript.

To a lot of folks it looks a lot nicer than

<label onClick={() => this.edit(this.state.todo)}>

There's a lot less noise, and it's _much_ friendlier for (most) designers.

I have never felt that I had to keep hundreds of gotchas in my mind while using vue. The syntax is extremely intuitive (unlike angular). Takes maybe one hour to read through the docs, and you have it.


> Have you ever made a graphql server with apollo-tools?

Have I ever mentioned apollo or graphql tools? Let me check: no

> There's a lot less noise, and it's _much_ friendlier for (most) designers.

I love how you could find exactly one thing out of a whole list of things that may be just ever so slightly better than JSX.

And of course, it's not better than JSX for very obvious reason that you chose to ignore: how { } in JSX accepts plain JS with the only exception that it has to be an expression. And (and it's the most important part): curly braces in JSX mean and accept the same thing everywhere in JSX.

In Vue though: What do @ attributes accept? What do : attributes accept? What do curly braces accept? etc.


My only point in mentioning apollo-tools is that DSLs are very powerful, and have the potential to make complex problems much simpler. SDL is a great example of is, as are vue templates. You may not appreciate the DSL, but, believe me, there are a lot of people who much prefer it. I'm specifically calling out designer type folks here.

> I love how you could find exactly one thing out of a whole list of things that may be just ever so slightly better than JSX.

It's not a question of "better" or "worse". It's a question of tradeoffs on spectrum of abstraction.

I'm not here to bash JSX or react. But you apparently are, and I'm just trying to open your eyes a bit.

When vue came out with JSX, I tried to force it on my team, and there are a serious backlash, to the point where I came to realization that the vue's major strength is actually the templates, and the magic.

You may not like the magic, but a lot of folks do.

As for your specific questions

@ and : are just short hands. That's like saying: what's the difference between `map` vs `reduce` in my component to iterate over an array. They _can_ do the same thing, but map is shorter. In plain JS I can do `i = i + i` `i += i` or `i++` to increment an variable.

@ just means "event handler". @click = "onClick" : just means "use a dynamic value for this prop { } you can put any JS expression, with the plus that you don't have to litter your code with `this`.


Additionally:

> with the plus that you don't have to litter your code with `this`.

"Littering code with this" is exactly how plain old vanilla JS works. Besides, "littering your code with this" very much depends on where your callbacks and variables come from... as in any old plain vanilla Javascript code. Because JSX is a paper-thin DSL on top of vanilla JS. Brilliantly and succintly described in this comment: https://news.ycombinator.com/item?id=17474370

In Vue you don't litter your code with this. You litter your code with hoisted variables and functions that are arbitarily hoisted into scope and injected everywhere. See my comment here: https://news.ycombinator.com/item?id=17471199 starting at "Of course. See inline comments."

The amount of gotchas and special syntaxes, and special cases, and the amount of moving part you have to understand to see where things come from and go to in Vue is insurmountably larger than in JSX.


> My only point in mentioning apollo-tools is that DSLs are very powerful, and have the potential to make complex problems much simpler.

Yes. But just because it has that potential, doesn't mean that Vue's DSL(s) are not without the many problems anf gotchas I described. Just because Apollo's/GraphQL's DSL is potentially good, doesn't mean that Vue's is. etc.

> It's not a question of "better" or "worse". It's a question of tradeoffs on spectrum of abstraction. > I'm not here to bash JSX or react. But you apparently are, and I'm just trying to open your eyes a bit.

My eyes are wide open. Where in JSX I see a uniform approach that works in all JSX contexts, in Vue I see several DSLs bound together by magic of the library.

> @ and : are just short hands. That's like saying: what's the difference between `map` vs `reduce`

Shorthands mean:

- new syntax. For all intents and purposes it's a new syntax (call it a DSL syntax). And you have to know the difference and gotchas of that syntax. You have to know where you can:

-- provide a thing that looks like a function ref

-- provide a thing that looks like a function call

-- provide a thing that looks like a bound variable

-- provide a thing that looks like a Javascript expression

etc. etc. etc.

And that is further compounded by the fact that `v-` attributes sometimes take single Javascript-like expressions, sometimes not (v-for), some have additional "arguments". some have additional modifiers etc. etc.

And of course, some of it is Javascript expressions inside strings (`v-` attributes), some of it is Javascript-like (but not really Javascript) DSL inside mustache's curly braces (inside tags).

So here's the original statement that started this thread: "The amount of special cases in Vue templating syntax is comparable to the special cases and gotchas of JSX"

This is demonstrably provably patently not so, as this thread has demonstrated.


I'm not sure attributes named as "ref" or "className" qualify either as Javascript or HTML


They qualify as JavaScript because className etc. are exactly how you work with HTML attributes from Javascript: https://developer.mozilla.org/en-US/docs/Web/API/Element/att...


The only thing that bothered me was that there wasn't a way to tell Vue to disable reactivity with a clear pattern: see https://github.com/vuejs/vue/issues/1988

So e.g. if you want to have a Leaflet map i.e. `this.map = L.map(...);`, Vue will automatically add reactivity to this property. Sometimes I had big problems with this behavior (or it was simply annoying), so I wrote vue-static based on ideas of the core developers:

https://github.com/samuelantonioli/vue-static

Now I can have big objects in the Vue component which don't get automatically tracked using the reactivity system.

- - -

A problem for many beginners:

Another problem with the reactivity system is that sometimes you have a route like `/employees/:id` and edit an object. But on abort, you want to rollback. One thing you always have to do is to copy the object you want to edit (I use lodash's `_. cloneDeep(obj)` for this). If you use Vuex, it's not such a big deal because it works using immutable state, but when you work with a plain javascript object this will definitely generate some headaches.

- - -

But otherwise, I think Vue is definitely the way to go. `v-model` can be seen as syntactic sugar while you have to add it to react inputs and textareas manually (using onchange and setState).

You can write stateless Vue code just fine and use JSX. On the other hand, React misses some of the cool features like the Vue component files (.vue files) and its templating language. And the best is: The framework doesn't say that you have to use it. It's not so opinionated but still feature-complete with the official plugins.


State management by process-directed messages is a really neat way to avoid throwing oneself under the OOP bus.

Furthermore, Elixir has Agent, a higher abstraction on top of Erlang/OTP gen_server that's easier to grok and use in many simple cases with no need to separate the public interface and OTP callbacks.


I've been using React full-time for a year and a half now, and I've never felt like pure-functional components are a good fit for more than a handful of use-cases. If all you're doing is displaying data, then sure, they're really elegant, but most UI code isn't a pure function of state; it also sends messages back to state, which means the two are tightly coupled, which means pretending they aren't feels gross and weird (I'm looking at you, Redux).


> most UI code isn't a pure function of state; it also sends messages back to state, which means the two are tightly coupled

I think this is what the Flux model is all about, making UI code actually be a pure function of state. By that, I mean literally a function, where state is the argument, and where all you render depends solely on said argument.

If you want to change what is rendered, you send a message and a Store deals with the state modification. Once it's done, it calls your pure function again, this time with a different state, so you get a different render.

This IMO, decouples state and and view instead of tightly coupling it. Redux is the best Flux implementation to demonstrate this IMO because it puts all state in a single Store. The messages to this Store can come from anywhere: UI, server, me typing on the console, etc. The state changes independently of the UI and in fact I could have a full application without having a UI whatsoever. Or I could have a UI without knowledge of my state's topography, because Redux lets me morph and cherrypick my state before I pass it to a component as props.

I think that's a good exercise: to try and build an application thinking of it as a series of actions on state first --and then how that may play onto UI-- to get to appreciate functional components. I'm curious to know why you think why you think Redux only "pretends" they aren't though. (:


Well because the UI isn't just a function of state, it's also a function of those actions (the actions have to literally be passed in to the rendering function). So there's bi-directional coupling between the UI code and the Store (the UI code renders from the state, and passes messages back to the store).

Also, conceptually, you often have a lot of state that's very directly concerned with and specific to the UI, and isn't just idyllic, agnostic "data". Things like "is this menu open or closed?" and "what's the current string value of this input (which isn't meaningful until the form is submitted)?" In Flux, those things tend to add a ton of boilerplate in terms of change actions, and split tightly-related concerns into separate corners of the codebase (if I remove this menu component I have to remove its open/closed state variable and the corresponding action).

To be sure, there's not really a great way to decouple things in the reactive architecture. I personally lean towards stateful components that are decoupled at their boundaries instead, which does carry its own downsides. The only solution I've ever seen that truly felt right was two-way databinding, which Vue (sort of) still has, but which has fallen out of fashion in general because it requires "magic" and because it tends to come with performance costs.


> Also, conceptually, you often have a lot of state that's very directly concerned with and specific to the UI, and isn't just idyllic, agnostic "data". Things like "is this menu open or closed?

The entire UI is specific to the UI. Trying to separate "entities" or "server data" from "UI concerns" is IMO a waste of time and just confusing.

At the end of the day, you have a state tree, and you project it to a UI. Where that data comes from and what it represents doesn't really matter. Events in the UI generate an log that can get folded into new state to then be projected again. These events could be generated by a button being clicked, or an XHR request completing, but that doesn't change the nature of the payload.

One important thing though, in most of these models, the state shouldn't be "is this menu open or closed". It should be "Is the user focused on an arbitrary task or not". The menu being open or closed is a projection of that. This way when your designer comes and says "No, this thing shouldn't be a dropdown menu anymore, it should be a modal", you don't feel the need to rename your arbitraryMenuOpen: true state key to arbitraryModalOpen: true instead. Saves a lot of time.

Elm is a pretty good example of how all of this works. Its fairly different from Redux and co (even though it inspired it a lot), but its interesting to see how all of these things absolutely can work. They get messy when retrofit into React and JavaScript, but it's not an issue with the concept, just the implementation.


That level of abstraction sounds nice, but isn't really practical. A dropdown menu and a modal have wildly different use cases and relationships with the rest of the app. The only way the former would directly translate to the latter is if the latter contains nothing but a set of radio buttons, in which case you should hire a new designer.

In fact, the reason we have the particular toolbox of standard GUI elements that we have these days is precisely because they serve different use-cases. Each serves a particular one, and the reason it's survived is because it isn't made redundant by any of the others.


> That level of abstraction sounds nice, but isn't really practical

The only thing not practical about it is that in these days and age, the amount of people with data modeling experience is low. But it totally does work in practice and is, IMO, the only way to really be productive with Redux. Otherwise any change you make or any new feature requires modifying components, actions, AND reducers. At that point you're just doing 3 times the work for everything.


I've seen this idea a lot from members of my team that when you use a state management library then absolutely everything has to go through that state management library. This results in some of that pain you describe with state that's specific to the UI. If you're still working with React, try keeping that menu or input state in the component with setState instead of putting it in the global state store. I've found that simple change to clarify our projects immensely by cutting out lots of unnecessary code and highlighting what state is actually important to the functioning of the application.


Yep, this is exactly why the Redux FAQ has a section with rules of thumb for deciding whether a particular value should go in Redux or not:

https://redux.js.org/faq/organizing-state#do-i-have-to-put-a...


That seems like a good approach. Still, it doesn't seem like the rendering code or the Store code could ever really be worked with in isolation. As I said above, picking a coupling boundary is like picking a poison. They all seem to suck for different reasons; I just personally tend to choose component boundaries.


I'd recommend starting with the application as an abstract entity: start with the state and not think about the UI. Once you build a data-model and action scheme from there, working a de-coupled UI is usually simpler.


> Well because the UI isn't just a function of state, it's also a function of those actions (the actions have to literally be passed in to the rendering function).

Wait, they don't though. That's the whole point of functional components. They are of the form:

    const Component = (props) => <JSX />
Where are said "literally passed" actions here?

> So there's bi-directional coupling between the UI code and the Store (the UI code renders from the state, and passes messages back to the store).

This isn't bi-directional binding. state determining UI, UI sending queued actions and actions determining state is one-way data flow. Bi-directional coupling would be tying a reference in the state to a UI element.

> Also, conceptually, you often have a lot of state that's very directly concerned with and specific to the UI, and isn't just idyllic, agnostic "data". Things like "is this menu open or closed?" and "what's the current string value of this input (which isn't meaningful until the form is submitted)?"

This is architectural, and is why components have their own state. Its up to you wether you want to keep this as application state or local volatile state.

> In Flux, those things tend to add a ton of boilerplate in terms of change actions, and split tightly-related concerns into separate corners of the codebase (if I remove this menu component I have to remove its open/closed state variable and the corresponding action).

Which is why I don't put it in the main application state (:

> To be sure, there's not really a great way to decouple things in the reactive architecture.

I mean, not if you're dumping everything on your application state, no.

> I personally lean towards stateful components that are decoupled at their boundaries instead, which does carry its own downsides.

Curious to learn what you mean by "decoupled at their boundaries". You mean components that are de-coupled from each other? You can make re-usable, functional or stateful components that are de-coupled from application state.

I think the main takeaway here is that not all state is the same, there's state that's part of your core application logic and state the component needs for its display only. Treating them as the same thing does limit the re-usability of your code and make dealing with your application state tedious.

> The only solution I've ever seen that truly felt right was two-way databinding, which Vue (sort of) still has...

There's other solutions (: I don't think Netflix, Facebook or AirBnB have all the state of their menus tied up with the state of their user data and and have all components be use-once because of that. Good state management can make things scale, and functional components very useful!

> but which has fallen out of fashion in general because it requires "magic" and because it tends to come with performance costs.

Yup. It's also hard to know where or how certain state is changing. It definitely allows you to build small applications very quickly, but it doesn't scale all that well.


Your state is tightly coupled with the actions that mutate that state, not the user interface itself. React wants you to define a higher order function for a button. The button will call that function, but the implementation of that function is only loosely coupled.


> I am never a fan of two way data binding as an alternative.

The author is wrong. Vue doesn't have two-way binding. It has one-way binding with events. Components can't force anything upon their parent's state with an event.


I mean, Vue calls it two-way data binding. From their website:

> "You can use the v-model directive to create two-way data bindings on form input and textarea elements. It automatically picks the correct way to update the element based on the input type. Although a bit magical, v-model is essentially syntax sugar for updating data on user input events, plus special care for some edge cases."

I'm not knowledgeable enough on the matter to say if this is or isn't, and to compare vs Angular, etc. But don't blame the author for this one ¯\_(ツ)_/¯

[1] https://vuejs.org/v2/guide/forms.html


"v-model" is syntax sugar emulating a two-way binding to simplify form creation. Under the hood it's a one-way bound prop, an event, and an implicit event handler. Ordinary events can't mutate state without an explicitly created handler.

  All props form a one-way-down binding between
  the child property and the parent one: when the
  parent property updates, it will flow down to
  the child, but not the other way around. This
  prevents child components from accidentally
  mutating the parent’s state, which can make
  your app’s data flow harder to understand.
https://vuejs.org/v2/guide/components-props.html#One-Way-Dat...

  AngularJS uses two-way binding between scopes,
  while Vue enforces a one-way data flow between
  components. This makes the flow of data easier
  to reason about in non-trivial applications.
https://vuejs.org/v2/guide/comparison.html#Data-binding


As discussed in https://vuejs.org/v2/guide/components.html#Using-v-model-on-...

  <Component v-model="foo">
is basically shorthand for

  <Component :value="foo" @input="foo=$event">
In particular, the child can't affect the value of the parent's "foo" attribute except by sending an event. This is in contrast to Angular 1 where changing "foo" in the child would also change it in the parent, which would often lead to confusing data flow cycles.


A shame that this answer was downvoted on a technicality.

As other people mentioned, Vue indeed doesn't have two-way binding, and v-model doesn't have the pitfalls that Angular had. It is just syntax sugar.

Maybe it's about time Vue people remove the mention of two-way binding from their websites, since it is being used to attack the framework. I've seen that in other discussions here in Hacker News.


Vue also has "1.5-way binding" with computed properties, which is what you normally need 2-way binding for, but without all the problems full 2-way binding might introduce.

Do you have any suggested resources for learning React in this way?


Honestly, there isn't much to learn. It's just a function that takes props and returns a React component (usually via JSX). The only big decision is the props API.

https://reactjs.org/docs/components-and-props.html

The best thing to do is just to brush up on functional concepts, thinking about things in terms of composition and application, and threading state through your application and flowing back through to the top via dispatches. Learn more about flow (the concept, not the framework). I like to picture a waterfall, where the water is state that always keeps flowing no matter what it hits. State should start at the top from some source, we don't care what that is, and then flow through the application down into the leaves. Functions can do transforms and reductions on state, but they should never hold on to state the way class components do.


My recommendation is to read through this: https://github.com/reactjs/react-basic


I wonder how you avoid writing stateful components in real-world complex SPAs.


Quite easily. The state is held in Redux or whatever, the only state held by components are UI stuff (is this section collapsed? Is this date picker open?).

In the last SPA I wrote there's about 100 components, less than 5 of them are stateful.


It's quite easy, I honestly think the only roadblock is how one thinks about computation. If you think of your UI as a single computational expression you're building up from functional composition, then the issue of state never arises. It's just about defining the shape of the interfaces.


Sounds cool but I can't actually imagine the way you described. :) Any tutorials, articles?


try working through some tutorials on erlang/otp supervisor trees. the concepts are very similar.


You manage your state outside your components, using Redux / Relay / MobX etc...


Discussions of this sort are often confusing. When one talks about using Redux or some javascript library to do "state management", I always wonder whether one is talking about application states (i.e. states originating from business logic but unrelated to UI) or UI states.


Application states. Redux isn't meant to maintain UI state.


110% agree


Have to do some clarification here on the point of "Unclear architectural patterns", as the article is way too misleading.

- The reason the API call is made at `created` lifecycle is that the video is a quick, 5 minute intro for beginners. Beginners, as in "people who are familiar building static websites using html/css/js". There is no need to bring in Vuex or vue-router yet. In fact the whole beginner example can be put into a single HTML file by including a Vue script tag. The approachability is what made Vue shine. Some other frameworks assume that you want a build tool, state management, client side routing etc and beginners spend hours configuring those tools and figuring out state management and client-side routing, instead of doing real work.

> To answer to my initial question: API logic should not be written in Vuex nor in components. There is even a good example on how do that in some of the official code examples.

- The example[0] clearly has the API logic in the Actions. The `/api` folder is a mocked API for illustration purpose.

[0]: https://github.com/vuejs/vuex/blob/dev/examples/shopping-car...


>Some other frameworks assume that you want a build tool, state management, client side routing etc and beginners spend hours configuring those tools and figuring out state management and client-side routing, instead of doing real work.

Okay, say I do the tutorial and build a simple page - how hard is it to retrofit routing or whatever to it? A lot of the time with new frameworks, if I get past the initial setup hurdle, I can't work out how to easily move away from toy apps to something I can use in production.


One thing I want to say is: Don't assume only developers make websites. Don't assume everyone wants to ship a heavy and complex SPA.

Example 1: A great typographer, Wenting Zhang, author of Type Detail[0], contributing to Source Han Serif, learning Vue to do some interactive widget for variable fonts[1].

Example 2: Brian Terlson on TC39. He's using Vue without Vuex or Vue-router to build an app to track TC39 discussions[2].

I hope we can admit that many people might not need store and router[3]. Store and Router are necessary for building complex SPA, but don't make them necessary, as many don't want complex SPA. They impose learning efforts in exchange of better architecture, but the imposed effort might not be worth it for many people who just want some data-rendering, some reactivity and some interactivity on their websites.

[0]: http://typedetail.com

[1]: https://twitter.com/DesignJokes/status/1015003288528400386 and https://twitter.com/DesignJokes/status/1014260361535647744

[2]: https://twitter.com/bterlson/status/913433979239436293 and https://github.com/bterlson/tcq

[3]: https://medium.com/@dan_abramov/you-might-not-need-redux-be4...


This will probably be downvoted but I have come to appreciate frameworks which are opinionated and target a specific use case than very general and trying to please everyone.


Thank you! That's a really good way to think about things and might be the push I needed.


AFAIK, with vue-cli 3.0 (that now includes a browser GUI) you can just add plugins to your existing project, and a router plugin should exist.

Previously on vue-cli 2.x, it was just a question on the project initialization step.


I'm not sure were the author looked for information about architectural patterns but there is a separate section on it in the documentation: https://vuex.vuejs.org/guide/structure.html

This clearly outlines a suggested structure for non-trivial apps, where API requests are separated from the state management. It also references the Shopping cart example as a guide.

Due to this glaring oversight I can't see any criticism the author has as valid in the section about "Unclear architectural patterns".


We adopted Vue 2 years ago and I've been extremely happy with it. It's very easy to get into, the learning curve is not steep at all, and for the most part it just works.

TypeScript support is mediocre. It's supported (Vue will let you use anything) but it's clearly a second class citizen.

There's also no real accepted best practices, which the author touches on (where do API calls go). Third party component design varies pretty wildly. I think this is just the reality of a young framework casting a wide net, we'll see what the future brings.

It's not perfect, but like the author, Vue was a great decision for my team.


vue 3 will be entirely rewritten in typescript.

https://github.com/vuejs/roadmap


And that will probably be the end of vue...


Why? The page clearly states:

Will be using TypeScript. For internal implementation only. Does NOT affect ES users, but should improve TS integration for TS users.


I haven't used Vue (and definitely not TS with Vue), but considering how easy it is to create type definitions for libraries written in ES6, if using Vue + TS is awkward (assuming its not because no one wrote a type definition for it), the only way it could make things better for TS users is with some refactorings to make sure types "follow along", and that totally would affect ES6 users. Anything that does not affect ES6 users would not affect TS users either.

An example of this is how in Redux, anything that uses the state in TS needs to add an annotation to type the store, because its completely decoupled (and thus theres no way for the state type to "follow"). Any way to make it follow requires some API changes (eg: creating mapStateToProp functions by calling a method on the store)


have you even tried to use TypeScript on a real project to say something like that ?


He's possibly meaning that if you completely rewrite framework it would lead to something like what happened to Angular when it was rewritten and promptly lost huge number of followers/users?


Angular didn't lose mindshare because of TypeScript, it lost mindshare because they completely changed the API of Angular, meaning a bunch of companies had to do expensive ports/complete rewrites/switch to new tech. A lot of companies are still stuck on Angular 1 for this reason.

Most Angular devs I know are happy to use TypeScript. (In fact going out on a limb, most JS devs I know).


In this particular case, with a BDFL in Evan, there's probably a much higher chance of maintaining sanity between major releases. People were worried about the change to Vue 2.0, but it mostly sunsetted features that complicated the framework and doubled down on an elegant component system. Seems obvious to say, but frameworks probably get fractured in geometric proportion to the number of powerful authors working on them.


Typescript is very similar to plain JS. The type annotation is purely optional. I really bought into the optional type annotation pattern when I learned and used Julia for a project. Typescript is also like that. It's extremely unintrusive to use and I'm quite sure such a huge shift as the one that happened in Angular won't happen.


That is amusing because Vue was already rewritten for V2 when they introduced the shadow Dom.


Was that really a thing though? People cried because they didn't understand the offer of better tooling.


I'm curious to know, what about Vue makes it easier to learn than React? It's just a function that takes in data and returns a piece of html. React also just works, and unlike Vue, it's worked for companies like Netflix, Wallmart, Facebook, Instagram, etc that have exceedingly complex requirements and require exceedingly fast rendering. What did you really buy with Vue over React?


For one: vue, vuex (centralized state library) and vue-router are stewarted by roughly the same people, which has a few benefits. The documentation is all pretty decent and uniform. I never sit for very long wondering how to do something.

Changes that break backwards compatibility are reflected across all three at the same time, and the correct versions are installed by vue-cli. I had several starts with react, react-router, and redux, and on almost every occasion something from my last attempt was broken because the api had changed, and the documentation changed with it (in the span of 3-4 months). That lead to several WTF moments. IIRC there was a period where react-router made some breaking changes from v2 to v3, and then less than a year later made more breaking changes for v4.

Vue is also a lot simpler to drop into an existing application. The .vue single-file component is very approachable, albeit a bit magic but about as magic as JSX. You can add a vue-loader for sass/less/etc. and simply specify lang="less" in these as well.

Vuex was a little easier for me to grok, although I had the advantage of trying out redux first. It has the advantage again of sharing documentation with the rest of the project.

Also, because react has worked for big companies as you mentioned, does not mean vue couldn't work for them as well. React gained a lot of momentum early among western programmers. Vue first gained traction in Asia - Evan You, the creator of vue, is from there. Also you might remember the massive amount of confusion for early React adopters regarding how to manage state. People liked react, but it only really had the view part ready out of the gate. Facebook's explanation of what the early-best-practice flux model entailed was vague, and there were several slightly different implementations.


I think the issue is that people keep expecting something from React that React has specifically stated it does not do, which is handle everything. It's always been a library, not a framework, to give people to freedom of choice to choose or omit other libraries or frameworks.

I remember working on Angular 1 projects, where literally everything from loops to http calls was mandated by the framework. Then everything suddenly became legacy. Angular was going to be completely rewritten, and everything I had learned was going to be tossed away. I still, to this day, have to work with projects that are Angular 1 code rot hell.

I think that's probably why I have never had the problem's you have had, because I never wanted to use React Router or Redux. Those pieces of functionality were easy to implement on my own. (Redux itself is incredibly small)

Personally, I think it's silly to use Vue. Angular had serious deficiencies and project mismanagement, and React was a real solution to those problems. I mostly hear either minor grievances from the Vue crowd, or no response at all as to why they switched (hype train most likely).

I also don't think Flux was vague, it just lacked an implementation. Again, there just seems to be a big fear in the JS community about writing code instead of pulling in a framework. React itself is just reactive functional programming. The sell of not writing it yourself is that you get to work with a nicer API while the React team improves the backend for you (a la Fiber).


> I think the issue is that people keep expecting something from React that React has specifically stated it does not do, which is handle everything.

You can't really have it both ways though: if you're going to say React doesn't do all those things then you have to accept that people who want something more streamlined and comprehensive should legitimately look somewhere else, and React is only for people who want to spend the time assembling their own solution (for some acknowledged benefits). Vue has taken the more comprehensive approach while still being pretty flexible, and therefore suits a slightly different (but I would argue, broader) set of people.


> I think the issue is that people keep expecting something from React that React has specifically stated it does not do, which is handle everything.

Ok, but people learning React - with no guidance from the library or its maintainers, as you said it's only the view - are going to search for "react how to route" or the like. They end up using things like react-router, and some of them run into problems like I did. You did ask originally what makes one easier to learn than the other.

> to give people to freedom of choice to choose or omit other libraries or frameworks. [...] Those pieces of functionality were easy to implement on my own.

And I listed some problems that I had using those other frameworks which were recommended to me. "Just do it yourself" isn't exactly helpful.

> (Redux itself is incredibly small)

Ok, but it has had some API churn as well - EDIT: I was wrong about this. See replies.

There's definitely boilerplate that goes along with it. There are libraries that deal with that to an extent, but there are many. Which one does someone learning choose?

> I remember working on Angular 1 projects...

What's that got to do with Vue? Vue isn't Angular.

> Personally, I think it's silly to use Vue. I mostly hear either minor grievances from the Vue crowd

I gave you my examples. You seem to compare only the view layer functionality. I'm examining the ecosystem and preexisting examples of how to implement functionality, which is going to be important for someone new to the library. Of course you can write this yourself, but for people trying to learn React, only having the view layer makes it more difficult to figure out how to "implement it on your own".

> I also don't think Flux was vague, it just lacked an implementation.

Not having any public implementation is pretty vague!

> There just seems to be a big fear in the JS community about writing code instead of pulling in a framework

Well, again, my response was from the perspective of someone learning React and how one might architect a SPA using it. As stated, there was no official flux implementation in the beginning, just a diagram from Facebook and some hand-waving documentation. Vue has official and router library and state management library which are linked to from the official documentation.

> React itself is just reactive functional programming. The sell of not writing it yourself is that you get to work with a nicer API while the React team improves the backend for you (a la Fiber).

You can apply this your own argument. React is just reactive functional programming. Why just pull in a view library when you can just render using functions? Why not write it yourself, if you're writing everything else yourself? Are you afraid to? Why include a 240kb library to render functional components?

What do you get out of using React over Vue, which also uses the virtual DOM and has functional components?


> Redux has had some API churn as well

Uh... what API churn? The Redux store API hasn't changed meaningfully since about a month after its 1.0 release. 3.0 came out around September 2015, and it's been the same since.

React-Redux has stayed API-consistent too, even though we rewrote the internals for 5.0.


Ah, It seems I was very unlucky as I started learning it right before 3.0 and tried to pick it up after 3.0. Upgrading my previous project gave me strange errors, and the documentation had changed with it, leaving me to puzzle over what had happened.


That must have been a pretty tight time window :) Per the releases page at https://github.com/reduxjs/redux/releases?after=v3.0.1 , you can see that 2.0 and 3.0 were only a couple weeks apart, and basically just tightened up the API around hot-swapping the root reducer.

Since then, the most meaningful API change was 3.1.0, which redid the `createStore` signature to allow passing an enhancer as an argument (as opposed to the original more FP-style approach).


Netflix, Walmart, etc. solve a much different set of problems than most shops. I'm proud to work for a small company with simple (but rapidly changing) requirements. :)


That doesn't answer my question. What about Vue actually made it a better choice for those requirements? In my experience, the fact that React is a simple view library makes it the perfect choice for small shops. You're taking on considerable risk when you use a technology without a vested backer (Facebook is heavily vested in React, look at Angular 1 for an example of a framework with a big backer than is not vested, the API was completely broken in a rewrite). Smaller frameworks also suffer from a lack of sustained development.


> In my experience, the fact that React is a simple view library makes it the perfect choice for small shops.

Vue is also a simple view library.

You keep bringing up Angular, as if Vue has something to do with it. Vue is so much closer to React than to Angular.

> You're taking on considerable risk when you use a technology without a vested backer (Facebook is heavily vested in React, look at Angular 1 for an example of a framework with a big backer than is not vested, the API was completely broken in a rewrite). Smaller frameworks also suffer from a lack of sustained development.

Sorry, but that sounds a lot like rationalization and wishful thinking, written purely to make React look good and anything else look bad.

Vue also has backers that contribute financially, a large community using it and sustained development. The fact that it isn't as big as React doesn't make it unworthy of existing or unable to provide the same technical benefits as React.


I evaluated react/redux and vue/vuex for a project . I wrote a small poc in both. This is why I chose vue

1. Js doesn’t support immutable data structures so trying to return a deeply nested model using spread and other things was ugly. The answer seems to be “flatten your data”. I didn’t have to flatten my model with vuex. Vuex uses mutations when I can keep a flat model of observable but also keep my pristine model that I can send back over the wire with no changes . I suspect mobx may do the same sort of thing for vue. I feel like the react pattern would work better with a language like clojurescript that actually has immutable data structures.

2. Prefer html to Jsx although vue does support jsx. Admittedly this is just a preference thing.

3. Less boilerplate. I felt like I was writing more code that didn’t really do anything useful in react/redux. Vue seemed to have the smallest ceremony to code ratio.

4. Vuetify seemed a lot easier to use and was more polished than the react counterparts. I know it’s just a widget library but I found it fantastic and the docs were great. Vue slots are a great idea

5. Documentation . Vue has second to none documentation and this is important when you are starting out

I build a medium sized app in vue and was astounded that I literally did not run into one issue. That has never happened to me in 30 years. Kudos to that team.

6. React router was on its 4th rewrite. I can’t deal with constant breaking changes

7. Router and vuex felt more cohesive and integrated into vue

Whatever you choose please do support these guys on patreon!


> You're taking on considerable risk when you use a technology without a vested backer

I hear this line a lot, and it reminds me of Warren Buffett's line about finding out who's swimming naked when the tide goes out. He's referring to unprofitable companies that get exposed during economic recessions, when their stock prices are no longer boosted by generalized positive sentiment (I'm oversimplifying).

In this context, I think frameworks get exposed when big company support gets withdrawn. Angular didn't always look like an abandoned beached whale. Initially, having the backing of Google made it look like a de facto obvious choice. But when support from a large backer wanes, it quickly accelerates the demise of a framework as what the halo effect previously presented as well-considered design choices are suddenly recast as clear mistakes in hindsight.

This might never happen with React. But if it does, it will be swift and loom with unmistakable signs in the rearview mirror.


That doesn't really answer the question. :) How does Vue let you deal with "simple (but rapidly changing) requirements" better than React?


Not really. It’s all the same set of problems.


Apart from anecdotal experience telling me that fresh JS devs have a much easier time with Vue than React, I love to still have the option to use it through a simple embed without a build system but can switch to a Webpack/any module bundler if the requirements demand it.

The JS ecosystem really has a problem with bloat in my opinion and Vue trumps React in the regard (react eject anyone?).


It's worth noting that React has _always_ been something you could add to an application with just one or two script tags, and the docs were recently updated to emphasize that use case: https://reactjs.org/docs/add-react-to-a-website.html


But writing React without JSX is really not that great in my opinion whereas writing Vue without any preprocessor is totally fine. I know there's the option to use a JSX browser compiler but it's not recommended for production.


Coming from back-end dev, I looked at both. React looked hard to learn because I (thought) had to pick up a huge amount of tooling knowledge. Vue looked easy to learn because its docs promoted a very incremental and piecemeal approach. I didn't need to learn about front-end tooling to build something useful. I started learning Vue. It was easy to learn. I haven't had a compelling reason to try React since then.


Our company used React when starting a new project, but we still had an existing project with a vanilla HTML/CSS/js website, which really needed a rewrite. I had a talk with my cofounder about the strengths and value of React, but hadn't dived deep yet - I wasn't working actively in the codebase of the new project. I tried to, and all the moving parts were monstrous to wrap my head around - states, redux, actions, whatever, even though I thought I understood the fundamentals of the reactive paradigm.

My cofounder suggested I check out vue for the rewrite of our legacy project, and I was able to onramp SO easily. I can easily hand off components to other team members to write, and it rarely broke stuff in the rest of the project. On the whole, vue feels a bit less powerful but a LOT simpler to wrap your head around while subscribing to the reactive UI paradigm.


You're talking about Redux, not React. Your website would have probably been fine with just React. React gives you the choice to avoid needless frameworks and choose the level of abstraction that best fits your project.


Nope, I'm talking about react. I'm aware redux is just another step in the "level of abstraction you may want to use". And the problem is that every level you want is a challenge to get started with in React.

For example, JSX is an abstraction level I'd like to use. It requires an npm install to set up to contribute to production code. It has already crossed the threshold of an easy on-ramp for say, an intern -- because if this involves a first-time npm set-up on their machine, there goes the rest of the week.

With Vue to start using another feature/abstraction layer, you never have to do additional setup (your html file includes the vuejs script already), you just read the syntax docs and get going.

Additionally, React (and redux even more, yes) involves much more boilerplate than Vue does for every new feature you want to use, which is often more verbose/obtuse and hard to parse for a junior web developer.


Looking at the Vue docs at https://vuejs.org/v2/guide/render-function.html#JSX , it specifically says using JSX with Vue requires a Babel plugin. How is that any different than React?


Your interns take a week to install npm? Good lord.

Sorry, in your last post you specifically mentioned only terms that apply to Redux. React has no concept of actions, reducers, etc.

If you read my top comment I specifically talk about React’s function component, which is the least verbose way to describe an interface across any framework. Unless you can think of something easier than (props) => <h1>{props.name}</h1>

Honestly you just need new interns.


> it's worked for companies like Netflix, Wallmart, Facebook, Instagram, etc that have exceedingly complex requirements and require exceedingly fast rendering.

I'm curious whether Facebook actually have any endpoints where exceedingly fast rendering is necessary because it'd be the bottleneck. Facebook tends to be really slow for me but I figure that's down to it being really slow fetching data.


I agree - the Typescript support isn't great... I was taking a look at vue + typescript and cobbled together something that worked but there was unpleasant weirdness.

I wasn't aware that vue3 was going to be written in Typescript - that is very welcome news.


Yes the weirdness introduced by TS, especially around vuex, is really jarring. But then again, last time I tried a new medium-sized Vue project in plain old ES6, I went running back to TS, weirdnesses and all. And bit by bit, especially with the evolution of vscode, vetur, and TS itself, the weirdnesses are getting better.


Typescript support has gotten much better in the past few months. In particular, the vue-cli scaffold provides the correct stubs so typescript doesn't freak out when importing single-file components.


Pushing so much support to chat is an astonishingly big mistake. Not only are platforms like stackoverflow vastly better at answering questions and providing long-term documentation, it also builds broader communities. People use things like "number of stackoverflow questions tagged vue" to determine health and activity. You don't want to miss out on those metrics that other libraries are rolling with.


I can vouch for the author's points on the good parts of vue.js.

We've built our single page application (SPA) web app with vue.js and are very pleased with the results -- https://checkoutclip.com. We were able overcome most of the stumbling blocks by looking up https://vuejs.org/v2/guide/, https://github.com/vuejs/vue/issues and https://forum.vuejs.org.

For server side rendered (SSR) pages, we're using nuxt.js, which is working out great as well. E.g. SSR page: https://video.checkoutclip.com/-LDQ5TtL_yywYCgUNb6K

I would recommend vue.js for anyone building their first SPA even if they don't have prior experience building one...it's easy to pick up.


Five (5) megabytes of JavaScript for a basic brochure site... I assume 99.9% of that is only necessary after signing up and signing in, not while unfortunately viewing the page on a less-than-flagship mobile device and metered data plan?


Welcome to web in 201x. This is not a problem exclusive to Vue.

With that said, the new vue-cli uses Webpack 4 now which can do code splitting, and you can code split on route also to make individual page bundles smaller.


It's going to change and get less hefty, we're looking into code splitting.


Vue makes it incredibly easy!


The new module system makes it easy ;)


Not to mention the images. The home page background image alone is 600ko ! More than the entire HTML.

Saving the site on the hard drive gives me a wooping 10Mo for a home page. with a menu, a few pictures and some text.

This is insane.


Have you looked at your site with javascript disabled? Additionally, was vue used just for the website or the chrome app as well?


Our site does't work with js disabled. Serious question: is it common for folks to disable js?

vue is used only for the web app. No js frameworks used in the chrome app.


It's not common. My site with hundreds of thousands of users has been using React/Vue for years and I've never had one complaint about JavaScript.

If JavaScript is disabled I just show a message saying the site needs it.

I also only support modern browsers and haven't had a complaint for 3 years.

About 3 months ago I completely dropped support for any browser that doesn't support CSS grid (no more IE 11!). Again, no complaints. This one is more "brave" but I use Modernizer and show a clear message outlining all the required features the user's browser doesn't support and why they would want that feature in a browser. There's a link to a website to help them find a modern browser on their platform.

Edit: I realised that based on what I said you could argue that users are annoyed but I'm just not aware. I doubt this is the case since the users are keen and vocal. I get messages almost daily from them telling me the features they want to see. The last time this had to do with browser support was one message 3 years ago about IE9 not supporting the TLS certificate or something. They were forced to use IE9 at work.


Without hard data, this is pretty meaningless. If I were to visit a site that didn't work correctly in my browser, I would close the tab and never give it another thought. I would certainly not take the time to write a complaint.

> I doubt this is the case since the users are keen and vocal. I get messages almost daily from them telling me the features they want to see.

Maybe existing users (and even for that, I'm skeptical), but how many potential users did you lose because they couldn't even open your app?

I'm not saying you are wrong, just that "users didn't complain" != "users weren't affected".


>If I were to visit a site that didn't work correctly in my browser, I would close the tab and never give it another thought. I would certainly not take the time to write a complaint.

And I wouldn't miss you.

I can make the service better faster if I don't support the lowest common denominator. I'm sure I'd lose more users if the website was bloated with fallback code and my development speed was such that features are a year behind where they are now.


I completely agree with this sentiment.

I absolutely hate the "does it work on ie6".

The time you spend dealing with old browsers is never returned in profit. I had one customer (ie10) in 4 years, and losing him cost me and made me nothing.


But dropping support for certain browsers/clients without having data on how many of your customers would be affected is silly, IMO. You might decide to drop support for IE 11 because you want to use CSS Grid without hassle, but then it turns out that 10% of your users use that browser! As with everything, you have to weigh the tradeoff, but you can't do that if you don't have the data to begin with.


> without having data on how many of your customers would be affected is silly

You're making the assumption I don't have and use data like that? That's an incorrect assumption.


Sorry, you are correct, I made that assumption. It seemed implied by your use of user complaints as a metric of success—I assumed that was the case because you didn't have hard data, so I apologize if that's not the case.


Not a problem at all. I place high value on being available to users of my website. I reply to each and every message. Perhaps it's a bit unusual for someone to talk about that before the numbers.

It has been my experience that I've gained more valuable insight from talking with users than I have from the numbers.

But, as a little Latina girl once said, why not both?


I think the other person was talking about quantitative data (e.g. from Google Analytics), not qualitative data from customer conversations / complaints.


Yes. That's also what I thought. I'm not sure why you think I thought otherwise.


How does your site sound/read in a screenreader like NVDA? [0]

0: https://www.nvaccess.org/


That's a really good point, and it's one of the drawbacks of designing a website for the 95%.

I haven't tested myself (I'm just one dude - there's a lot I'd like to do but haven't yet), but I see no reason why it wouldn't work well. I try to design semantically and everything is rendered server-side.

But, in reality, I don't think this is the kind of website that would be usable for a blind person anyway. There's not really anything to read. There would be much better ways for a blind person to get information than using this website.


Vision impairment is a spectrum, so someone who can see to some extent may be using a screen reader to assist. People might be using your site at 150% zoom, etc etc.

One thing you can do is put a note somewhere easy to find that says "if you require assistance using this site, email someone@domain.org". Sites that I've worked on also had a phone number here but I understand that's an edge case.

You also mentioned alternative ways to get information - if there's ones you can link to (without linking to a competitor or whatever), there's no reason not to provide links.


Hi voltagex, thank you for your input.

I don't think this is the kind of website where I "help someone to use it". Instead of speaking in the abstract I may as well show you so you can see what I mean:

https://pricehipster.com

As you can see, the whole point of it is designed around quickly glancing at prices. And I don't think it makes sense to tell people other places they can find prices if they can't see well enough to use this website.


Okay - that makes sense.

It's been a while since I looked at things like this but have you done simple stuff like check whether the colour contrast ratio [0] meets WCAG standards?

What about making the orange highlight work when tabbing through the website with the keyboard?

What about having a Skip Navigation / Skip to Content link? [1]

0: https://webaim.org/resources/contrastchecker/

1: https://webaim.org/techniques/skipnav/


Yes I keep those things in mind while developing. I may have missed one here or there, especially in any code from my early days of development.

Thanks for the link about "skipnav" I haven't heard that term before. I don't really see how that can fit in, though? I guess the category links right at the top of the page is the closest concept?

It doesn't make sense to skip down to item number 200 since there's no way to know what's down there. Best to look at items 1-199 first. That is the same for all users.


It's exactly to skip to the main block of content - every item in the nav menu may be read out individually (or at least needs to be tabbed through) otherwise.


Oh I understand now. It's skipping the menu itself. I don't know why I misread (skimmed) the link you posted. Yeah, I can see why that's useful. I'll add it to my to-do list to look more into that. Thanks!


I find their recommendation skipnav somewhat ironic - pages on that site with any sizable contents don't show any actual content until after the fold on my macbook, e.g. https://webaim.org/techniques/css/invisiblecontent/ .. the entire first page consists of various forms of navigation.


Haven't tested, I intend to make it possible. Thank you.


I haven't checked recently, but JAWS [0] is probably the dominant screenreader still - NVDA is the open source alternative. Ideally you'd test in both

0: https://www.freedomscientific.com/Products/Blindness/JAWS

Edit: using a screenreader effectively is a skill in itself. There are consultancies around accessibility testing. I am not affiliated with any of them.


> If JavaScript is disabled I just show a message saying the site needs it.

We don't complain, we just go somewhere else.


And I don't complain when you go somewhere else.


Good to know, thank you.


Well for what is worth, I had been thinking on the idea for a while after growing tired of so many scripting and tracking everywhere, and I felt encouraged to make the jump and disable Javascript after reading this comment in HN (thanks bmurphy!):

> The single best improvement I've made to my mobile browsing experience in years wasn't getting a new faster phone, it was installing Brave and disabling javascript. [1]

To be honest, (s)he was right. But at the same time, it's disgusting, and plainly bad, to see how much of the Internet is _broken_. Which by my definition means requiring JS even to show some text and images on a web page.

I understand that more advanced features might require some scripting, but come on, I'm pretty sure that's not the case for printing some good old letters and pixels on a browser window! And still, lots of places seem to not know how to do it without dynamic code all around. (I'm not talking about this specific site, in any case. Just felt like ranting.)

[1]: https://news.ycombinator.com/item?id=14153588



> Our site does't work with js disabled.

Then please have a noscript tag.

> Serious question: is it common for folks to disable js?

That's not the only reason you'll find for JS being unavailable.

Windows Updates has managed to disable JS in various situations across both Edge and IE over the years due to tightening security policies.

Chrome has had V8 crashes over the years, as has Firefox.

The browser might be misbehaving, but rarely will the user attribute it to the right place - your site will get the blame.


It's best to use some sort of server-side rendering so you get the best of both worlds.

JavaScript-only is not friendly for SEO.


Agreed! We're working on prerendering some pages -- https://ssr.vuejs.org/#why-ssr .


I usually leave it enabled, I just tested it when I viewed the page source and saw very little was there beyond JS. I guess I come from a different time where you used as little JS as possible/was required.

I'm also not familiar with vue so I was trying to work out if it was used to build your web page or the actual chrome app. The web page is fine but I just wasn't sure where vue came into the picture for such a simple site.


I've used React full-time at work for a year and a half now, and I did a personal project in Vue for a while to try it out, before converting it to React.

There are some things I really, really hate about React. It is not kind or accommodating (Vue is both of these things), but it gives you control. I was head-over-heels for the first few days of using Vue; "breath of fresh air" is exactly the phrase I'd use. But the project I was using it for was an IDE of sorts, and eventually I just needed more control than it allowed for.

If someone told me they were going to build a basic website - not a web app - with React instead of Vue, I would laugh at them. Vue truly is a successor to jQuery for the reactive age. But for really complex applications, it's too "magical" in my opinion.


I choose Mithril.js regardless of the apps complexity nowadays. I've built apps in React and Vue and do agree that Vue is the logical choice over React but I don't see it as ground breaking or magical. I see Vue for what it is, A JavaScript framework that gained popularity by being included by default in the Laravel framework and now has good financial backing.

Mithril.js is a framework that is truly "magical" in my opinion. I mean its 8kb, includes routing and XHR Utilities out of the box. Faster render times than Angular, Vue and React. You can write HyperScript or JSX. The syntactic variants allow you to write your components as ES6 Classes or closures. Lifecycle methods, a render and mount option and the list goes on and on. People tend to dismiss Mithril because it's a lesser known framework but it has a vigorously thought through programmatic approach and you've got a direct line with the maintainers, you cannot match that.

Sure, each to their own but calling Vue "Magical" is an incorrect assessment.


I also use Mithril, and in my opinion, it's less "magical" than React in the sense that the GP is using[1].

When I ran into an issue using React, tracking it down was extremely difficult (by the end it was just "difficult" due to improved tooling around react). Mithril is small largely because of its simple implementation, which makes debugging a joy.

1: They seem to mean magical in the sense if "I'm never going to understand how it works"


Vue reminded me so much of Ember that I could not understand how people could think of fresh air...


Embed is more complicated than vue to use. Vue has components. Updating the dom is mostly mutating your component attributes. That's it. Nothing else.

With ember you got controllers, models, inheritances, many special methods...

The VueJS documentation also makes it easier to get in. The Ember beginer tutorial starts with a full fledge app with a cli to install and use and features routing and addons O_o


> Vue has components. Updating the dom is mostly mutating your component attributes. That's it. Nothing else.

How long have it been since you at least looked at Ember?

> With ember you got controllers, models, inheritances ...

You use those now only when you choose to or not at all.

> ... many special methods

= adding features Vue does not have.

> The Ember beginer tutorial starts with a full fledge app with a cli to install ...

Ember-cli is something everyone is desperately trying to copy. Even Vue!

Sorry, but this sounds like generic anti-JS-hate: tons of misinformation to bash something you have no clue about.


The Vue components remind me very much of Ember components, that's what I wanted to say.

All that templating and two-way-binding stuff.

Sure, Vue goes a bit more in a lean direction, because it doesn't offer as much out of the box as Ember, but the idea behind the components seem to be similar.

React or Angular (>2) have entirely different approaches, from one another and from Ember/Vue.

They felt fresh to me.

More

Guidelines | FAQ | Support | API | Security | Lists | Bookmarklet | Legal | Apply to YC | Contact

Search: