Removing User Interface Complexity, or Why React is Awesome
jlongster.com
jlongster.com
I have two concerns with this approach. Take everything I say with a grain of salt as one of the authors of Ember.js.
First, as described here and as actually implemented by Om, this eliminates complexity by spamming the component with state change notifications via requestAnimationFrame (rAF). That may be a fair tradeoff in the end, but I would be nervous about building a large-scale app that relied on diffing performance for every data-bound element fitting in rAF's 16ms window.
(I'll also mention that this puts a pretty firm cap on how you can use data binding in your app, and it tends to mean that people just use binding from the JavaScript -> DOM layer. One of the nicest things about Ember, IMO, is that you can model your entire application, from the model layer all the way up to the templates, with an FRP-like data flow.)
My second concern is that components libraries really don't do anything to help you manage which components are on screen, and in a way that doesn't break the URL. So many JavaScript apps feel broken because you can't share them, you can't hit the back button, you can't hit refresh and not lose state, etc. People think MVC is an application architecture, but in fact MVC is a component architecture— your app is composed of many MVCs, all interacting with each other. Without an abstraction to help you manage that (whether it's something like Ember or something you've rolled yourself), it's easy for the complexity of managing which components are on screen and what models they're plugged into to spin quickly out of control. I have yet to see the source code for any app that scales this approach out beyond simple demos, which I hope changes because I would love to see how the rubber hits the pavement.
It's always interesting to see different approaches to this problem. I don't think it's as revolutionary as many people want to make it out to be, but I've never been opposed to borrowing good ideas liberally, either. Thanks again, James!
Blog posts are best when they are sensational, and I try not to overdue it. I think React has a lot of good ideas, but "revolutionary" is a strong word. I think "refreshing" is a better word. Regardless, I think both React and Ember are the best 2 solutions out there right now, with quite different philosophies, and I'm happy that users have a choice.
Using rAF in my post was pretty much a hack. I think it was fun to take that and run with it. When you use React though, you don't actually do that, you use its `setState` method, or you use something like Cortex. If you look at my cortex example, you do use setters and getters, which give you a way to notify data change. Why don't we just use models like Ember? Because React still doesn't care how we model our data -- even if we have to call `set()` to trigger a paint update, what we get is the choice to use something like persistent data structures for our models.
=== I was completely wrong about Om, it does not continuously trigger rerendering/diffing ever 16ms with rAF. It only uses rAF to batch rendering, so multiple repaints are throttled to a minimum of 16ms ===
The on-screen issue is interesting; I need to think about it more to see if we can actually leverage it in production apps. I think we can for large list views. You don't share scroll state, do you? I absolutely agree that too many JS apps are breaking the web, and I love that Ember has defaults to make that not happen. There is a grave danger in using React and not taking care to do things right.
I'm actually really, really happy about the idea of React and Ember being the 2 ways to choose to build webapps. I have the upmost respect and love for Ember, I think it does a lot of things right, and I wouldn't be surprised if things like routing wasn't copied for libraries to use for React. <3
That's got a couple of issues.
1. It eats my battery
2. It DoSes my machine (10-20% not available for other things)
So, please don't do that. Set a `dirty` flag, call a `setState` or something that requests just 1 rAF or queues a task to re-render or something and then go back to sleep.
But it was a neat way to go from something very simple to more complex.
It appears you're using a multicore machine with between 5-10 cores. A continuous loop is basically going to keep one core at 100%, which is only a bit of an annoyance with a multicore, but on a single or even dualcore machine (e.g. low-end mobiles), it will make everything else slow to a crawl.
It's interesting to note that, were this done several years ago or earlier, it would only make people complain about how your site froze their browser, but now we barely notice a single core running at full load unless we're observant...
Please use computing resources responsibly.
Not to mention that, even on a high-end laptop, that will drain the battery very quickly and burn your lap in the process.
I would be curious why it's at 10-20% though. If they don't touch the DOM and their checks are quick (just a pointer as the article says) then there's some crazy serious overhead in the browser or somewhere just to call into JS once every 16-17ms and have it go back to sleep.
It would be interesting to look into where 10-20% is going. It seems like in a perfect impl, a mostly no-op rAF should take 0.001% or something along those lines.
To quote TFA:
> A set method to change state could trigger a rerender (React has setState), but there's an even easier way to react to changes: continuously call renderComponent with requestAnimationFrame to repaint the UI, and only change the DOM when the component returns different content.
Edit:
I was mistaken about how Om works. I was under the impression that Om scheduled a rAF every 16ms to check for state change. In fact, it only schedules a rAF once the state changes.
However, this relies on being able to listen for state change from the underlying model data. I was under the impression that one of the benefits of Om/React was that you could use its data bindings with any JavaScript library, even if it hadn't been instrumented for property observation. Instead, it seems that with Om, you are limited to consuming data structures that implement its state change notification interface.
There is no such limitation about what data structures you can use. There is no state change notification interface for data. Components can update their local state - no notification required here. Updates to global information (the application state) triggers a re-render from the root component of the application. Because of persistent data structures these updates can be done in logarithmic time as we never compute React UI subtrees that depend on unchanged data - it's just a reference equality check (JavaScript ===) in ClojureScript for any given piece of data to know whether it's changed or not.
Also, your comment, to me, shows there is still some confusion regarding Om's internals:
> However, this relies on being able to listen for state change from the underlying model data. [...] Instead, it seems that with Om, you are limited to consuming data structures that implement its state change notification interface.
Actually, the interface used is ClojureScript's flavor of STM: you set your app state, generally a hash-map, in an atom. When you mutate the app state via `swap!` it is published to Om -> React -> render. This may seem like a pedantic distinction, however, the key point is that you are required to use an atom which controls app state mutation. You could also use strings and vectors as your app state if you so choose.
Om, however, does not call requestAnimationFrame in a continuous loop; it calls it only when the state changes.
(To be fair, jlongster's article originally said that Om also rendered continuously, but that has now been corrected.)
What I find good about Ember/Angular is that they are very particular about how your app should be constructed. When I started writing single page JS apps, I didn't know what the best practices were. If I had started with Ember, I would've learnt. If I had started with React, I would have been making it up as I went along. If you know what you're doing, maybe that's good. For me, I find that I really like having Ember tell me how to structure my app.
I have a Javascript game client that does rendering optimization by comparing a 79x25 grid of numeric values with JSON data it receives from a server. That is just short of 2000 items, and it is enough to stymie older versions of Firefox running on Core Duo machines. I also queue things, and in fact, the "diffing" and the rendering happen in two different rAF frames, and it's still a challenge for older versions of Firefox running on Core Duo machines.
I wonder if this sort of benchmarking been done on different machines and different versions of the various browsers?
You can end up making an app with quite a number of elements flying around.
A neat pixel editor example: http://jackschaedler.github.io/goya/
After all the excitement about Angular for example, I went to learn about it and just got lost with new concepts: DOM transclusion, scopes, services, directives, ng-apps, controllers, dependency inversion and so on. I can use it but need someone to hold my hand. It reminded me of Enterprise Java Beans.
But so far just learning how React is put together and looking at the tutorials it seems like less of a framework and easier to understand altogether. I suspect this might become the new way to build web applications.
Well anyway, don't take this too seriously, I as said, I am an outsider to this.
AngularJS has a serious "naming" problem.
Most these concept are easily understood when explained the right away,what AngularJS doc doesnt do. The only complicated thing to grasp is the digest cycle. But anything else is trivials.It's nowhere near the complexity of Java EE.
Scopes are easy,like any composite structure you have nodes with children and parents ,what make scopes special is that they can inherit properties from their parent scopes.
Directives are just custom html elements/attributes where you should do dom manipulation,all other angularjs components should be free from any DOM manipulation,Directives are the closest thing to react components.
Controllers represent the state of the view,when the data in a controller changes, a view that exposes that data changes and vice et versa.
Services are dumb objects that can be shared between controllers and dependency injection is the way one share these services. Controllers can references services ,and services can reference other services. Services are singletons
So there is nothing really complicated with all these concepts,just that the doc sucks for some reason.
Angular attribute directives would map well to React Mixins. They take more work to set up, but with mixins code can at least be reused outside of the inheritance tree.
React? I grok that.
I went through this transition in late 2007, where the app my team was building gradually outgrew simple javascript libraries, and i ended up adopting extjs (the ember of its day) at great cost, but to great benefit. It is 600 kb of js code uncompressed just for the framework, and we not only ended up using all of it, but building a ton of code on top. We needed all that complexity to build the app we work on, but then it is over half a million lines of code by now. If you don't have those needs, the big js frameworks can be more trouble than they're worth, sort of like j2ee vs php.
I myself prefer frameworks that are minimal, least invasive and plays nicely with pure JS/HTML instead of treating them as bug. So anything that requires me to call .createClass to create an instance is out. Personally I've used Knockout.js pretty successfully. I think any average js dev can understand that framework in 15 minute and be productive. Although it's not perfect if you you are looking for idealistic MVC implementation.
For another example of a post that takes advantage of the dynamic nature of the web page, check out jlongster's sweet.js tutorial[1]. It's a tutorial on writing macros with JS that you can actually interact with (you can make modifications to the example code snippets and see your macros expand on the fly). Very cool.
WTF? I don't like reading things on the left side of my monitor, so I make the window wider to try and put the text back in the middle. Except now the demo area gets even wider (why? you don't use it for anything but tiny things?).
As I scroll, the various iframe loads create annoying jank, and to top it off, there's a bug at the end of the post where it moves horizontally for no good reason.
If you're going to do stuff like this, you need to polish it waaay better. This reminds me of the UI animations in the new Firefox. A good idea ruined by implementation, would've been better to leave them out.
Desired Reaction: Oh cool, a demo popped up just when it was needed.
My Reaction: Huh? Ugh, that's annoying. Wow, and I scroll back up and it moves again; I didn't ask for that either.
https://github.com/swannodette/om
I've not used vanilla React, but Om is certainly fantastic and apparently adds a bunch of stuff that's not in the JS version.
Also, a web framework written by the guy that wrote most of the language you're using? Win!
* Immutable data (you can get some of this in JS with Nolen's Mori http://swannodette.github.io/mori/)
* Better functional programming than Underscore (map :mykey some-objects)
* Great syntax: homoiconicity, thrush operator, first class set, regex, map, vector syntax
* Macros!
* Use of cool frameworks: Om, core.async
* Same language as back-end if using Clojure
It was quite frankly intimidating to get started with it all as an ex-Java/Obj-c/Python/JS dev but I could never go back.
I wish OReileys would issue an expanded version of their Intro ClojureScript book!
Get comfortable using Lein and editing your project.clj, then check out this plugin:
https://github.com/emezeske/lein-cljsbuild
It's a big investment but learning Lisp will repay you. There's tons of classic CS literature that you'll now be able to unlock and immutability really is the future, so it's good to start getting acquainted with it.
It would be great to get the AMAZING clojure-community ideas into the JS world.
I'd argue once you go beyond "small" things though switching to ClojureScript is preferable to duplicating large parts of its functionality in separate JS libs.
It has some of the core features
- immutable data - immutable vdom - global state atom, no hidden local state. - no manual DOM manipulation code (read or write). - a single top down flow of data from input to output - Events and Signals from FRP that can be manipulated using pure higher order functions.
etc.
As a bonus it's very modular, so if it doesn't fit your needs at least some subset of it will.
I think the key to making React take off is building a centralized repository for components that are open source. Then building your webapp would be as easy as importing the components you need:
bower install react-navbar
bower install react-signup-form
bower install react-sso-signin-form
I think this is definitely the future of how front end web development will be one day.One of the key requirements for this was a way to run untrusted scripts client-side (server-side is somewhat easy), since the platform lets users write arbitrary UI components. React works wonderfully here (in theory); we can isolate the React component in a sandbox (iframe with sandbox attribute set) and copy the Virtual DOM back to the main window after sanitization.
Add:
The beauty of React is that the developers recognized the limitations of other approaches; components in web apps cannot be solved with a rehash or an improvement on existing ideas. Giving up the usual design patterns and DOM hackery in favor of an esprima-based Javascript parser and serious Math is some creative thinking.
1: Open source, will have an alpha in 3 weeks: https://github.com/jeswin/fora
If so this will be very useful, especially since it sounds like it will allow us devs to spend more time on the business specific logic, and making the interface beautiful, instead of spending lots of time gluing together components and models.
The social aspect is equally important:
- There are millions of developers who don't participate in improving apps today because creating and hosting an app isn't a friction-less process. On Fora, if you see an app/forum that fits your needs, click fork, edit some JS+React/JSX in the browser, and you have a new app.
- Everybody sees all source code for all apps/forums; so it's great to learn. And then improvements help everybody. Like wikipedia for code. .
- Many people know enough JS to tweak stuff. React mostly takes just JS knowledge, so you don't need to know the framework like Angular. Ah, and also isomorphic UI code that runs on the server and browser. Also for all it's issues, one thing JS has going for it is that you can read and edit in a browser.
Ah there; I got excited. :)
Specific to your suggestion, which I think is awesome, is the idea of composibility. The easiest kind of component to write is a large component with lots of options, like jQuery plugins. This is the hardest kind of component to use outside of its intended use case.
What makes Angular so good is that the core directives are all extremely composable. They can be used all over the place without hacking.
To make your dream come true we as component authors must design carefully to make smaller, more focused tools, rather than large components, because large components are harder to adapt to applications outside their main use case.
I wouldn't be surprised if React was kept intentionally newbie-friendly, too.
[1] http://bower.io/
edit: the parent comment originally referenced a theoretical `react` command and didn't mention bower, which is why I brought it up.
Unfortunately, my best attempt at an analogy is Visual Basic controls, which might not be a great precedent, but the idea itself is a good one.
The confirmation popover you link to is a good example. It's a black-box component which exposes a fairly minimal interface. The constructor for this component works like this:
new ConfirmationPopover(msg, [title])
To attach the popover to an element you need to do: popover.show(el, [fn])
However, if we take another component from the same library, the swipe component[1], we see different conventions. Its constructor: Swipe(el)
It also has a show method which takes totally different parameters: .show(i, [ms], [options])
This is why I describe such systems as package managers or library managers - they're just a way of importing and exporting code and don't do anything to aid reuse. They're not particularly likely to play well together, lack standard interfaces and are almost certainly not composable in any meaningful way.React components are different because React defines some standard details of how components behave, how to extend them, how to inspect them and pass data back and forth. Components can contain other components, and all components have a relative place in the render tree. This makes possible standard developer tools that can be used to observe and inspect components in a DOM-like tree structure[2].
So, you could certainly use bower to distribute React components. What's different about React isn't how the code is distributed but the fact that you can have expectations about how, say, a React photo gallery component would behave that you would not get from some other JS library.
[1] https://github.com/component/swipe [2] http://facebook.github.io/react/blog/2014/01/02/react-chrome...
However, it would be more convenient if there was a distinction between packages that are designed to be UI components, and packages like AJAX libraries, async, and other logic libraries, which are a better fit for bower.
Distributing the UI components via bower is doable, but it wouldn't be nearly as nice as a dedicated component ecosystem where it is easy to search and discover relevant React components.
* A picture of what the component looks like
* How large the component is in KB
* Which CSS frameworks it requires or supports
* Cross browser support information
Bower is a very simple package manager right now with little information about the package beyond its name, a line of descriptive text, and a link to the Github.Overall the experience would be better for React devs to develop a customized package manager interface well suited to the type of packages being delivered.
Of course there is nothing stopping UI component creators from distributing their components on both Bower and a React specific package manager, but I think for purposes of discoverability a React specific one would be better suited.
https://news.ycombinator.com/item?id=7738511
Long story short, React has a much more graceful system of making the components generalized instead of the adhoc system that Ember and Backbone use.
Ember and Backbone have features that are similar to components, but components from two different sources will rarely work well, because often one component will break another. Anyone who has tried to put a bunch of different Backbone views from different people together has probably experienced this pain first hand.
React is designed from the ground up to allow components to work well together.
Can you also expand on what React design decisions has made vs. Ember that allow components to work well together? We've spent a lot of time thinking about creating a unified interface for Ember components, so I'd like to better understand where it's broken down for you.
my point is that it's a people problem as much as a tooling problem. or is it impossible to build incompatible React views?
i'm currently working on a library that makes it easy to share patches (GUI included) for audio applications. i'm using React. one problem i struggle with is that without my own additional standard, nothing is preventing anyone from making a component that can't patch in. which is the same problem i would have if i were using Backbone.
if you're looking for a "standard" way to share components you need to make assumptions about what type of GUI you are building- not just how you are building it.
What are the other libraries out there that we can use for this virtual DOM pattern right now? I only found mithril[1] that similarly does the template rendering with Javascript but I still don't know how different to React it is in the end? Is the diffing algorithm similar? Do they handle corner cases the same (many attributes need to be treated specially when writing them to DOM)?
Simplifying it a bit: other than the virtual DOM, is the rest of React also the best way to structure apps? What would the ideal "barebones" virtual DOM library look like?
I'm not familiar w/ React's implementation, so I can't speak for them. With Mithril, the diffing algorithm is basically a recursive tree diff. In addition to diffing at the attribute level (and taking care of some broken edge cases), it can do things like detect parent changes and reattach unmodified trees to new parents, if needed. I generally don't like corner-case-specific optimizations because I believe there are better directions to explore in order to improve performance (Mithril has a concept called SubtreeDirectives that I'm planning to expand on, for example). At the end of the day, one has to ask themselves if loading and parsing code to handle a bazillion rare corner cases is really significantly better than just doing the naive thing. The benchmark on the Mithril homepage seems to suggest that being minimalist performs better at the worst and arguably most important case (the first render).
Mithril in its entirety (with router, promises, ajax, etc) is ~500 lines of code (vs Bloop's 250) and the diff implementation has gotten more and more robust over the course of v0.1.* thanks to the Mithril community. I'd love to be proven wrong, but I'm seriously doubtful you can get a better balance between leanness and robustness elsewhere.
Re: best way to structure apps: I just posted an article ( http://lhorie.github.io/mithril-blog/an-exercise-in-awesomen... ) that ports some of the examples in this article over to Mithril to see how the two compared. My conclusion was that it's definitely possible to structure apps in a React-like style with Mithril. There a lot of benefits that this structure brings to the table, and using well understood design patterns effectively can go a long way to complement the componentization paradigm.
I don't force any particular implementation of the MVC pattern with Mithril, but I try to always organize code following the classic MVC pattern in my own code. My blog is partly an effort to document the techniques that can be used to support a liberal MVC pattern without necessarily committing to React's OOP paradigm or whatever.
In order to get adopted, React needs to coexist with existing applications/third party libraries that do manual DOM mutations. The life cycle methods are there to deal with this.
React implements its own class system that supports mixins and type annotations. The plan is to change the API to use ES6 classes (we're working to improve the standard to support all React use cases).
React re-implements its own event system in order to make it fast, memory efficient and abstract away browser differences.
Making composable components is not as straightforward as it first seems. There are a lot of edge cases like refs, owner/parent to be handled.
Then, as you mentioned, there's the diff algorithm and batching strategies which need to be implemented in a performant and memory efficient way. And provide hooks for the user to be able to give it hints via shouldComponentUpdate.
An ideal "barebones" virtual dom library looks like https://github.com/Matt-Esch/virtual-dom . The `virtual-dom` module was build out of frustration with the readability of react source code and is the minimal modular subset.
I've also built a small framework on top `virtual-dom` to add in essentials like immutable state and event handling ( https://github.com/Raynos/mercury ). Whilst mercury might not be the best way to structure apps, it's an approach that is getting me far and I'm drawing strong inspiration from FRP and FP systems like Elm and om.
It has many folders because the `vtree`, `vdom` and `h` are fundamentally seperate concepts.
Again each one is seperated into it's own files, this allows you to just require the `is-x` functions or the `diff` function alone without having to depend on the entire implementation.
It's also easier to maintain code if it's not one big file.
There are plans to break vtree & vdom out
- https://github.com/Matt-Esch/vtree - https://github.com/Matt-Esch/vdom
Note `vdom` is an implementation detail, we could also write `vcanvas` or `vwebgl`
In Firefox 29.0 on Ubuntu 14.04, the left sidebar with the text of the blog disappears and is replaced with a white space. I do not experience this on Chrome.
(As someone who doesn't work much with Javascript I thought the explanation was enlightening, BTW)
The best resource is to follow the tutorial (link below). The tutorial explains everything you may have a question about when comparing it to Backbone, Angular, or Ember.
http://facebook.github.io/react/docs/tutorial.html
I also found the IRC channel to be very, very helpful.
The only downside is that you still have to rely on other tools to make a true SPA like routing.
I developed a rather complex SPA with Angular recently and I cannot go back to the ghetto that is jQuery when using server side rendering.
With React, you can basically store all you data (state) in the root component (which could be the root of your entire page), and replace that with new state without thinking too much about the DOM updates and view changes that result from this.
This is perfect for a server-side framework, because such a framework by definition already renders everything whenever something changes (page refresh). Without React, the framework does a bunch of things and finally craps out objects that are transformed to HTML by the view (where the views are as 'dumb' as possible). With React, instead of rendering the object to HTML, you just pass these objects, as JSON, to a React component (which could be the whole page), and it figures out what needs updating. You don't have to deal (as much) with client-side logic if you don't want to, and things will still be performant.
This also significantly simplifies server-side rendering, to the point where it might require only one extra call to render the component server side (the handy renderComponentToString).
Of course, in practice it's often not quite that simple, but because of how React operates, you can get pretty far with relying primarily on the server-side framework and little logic on the React-side of things (plus you can achieve the 'holy grail' of seamless server- and client-side rendering.
(apologies if I'm getting things wrong, by the way. I'm by no means an expert on these matters and only just diving into React.)
The data portion is the main reason I was looking at Angular.
Thank you.
Does that answer your question?
As your app grows, it might become inefficient to send down the now-huge JSON object, and you might want to add some client-side logic to deal with that. However, this might not even be necessary, as 1) even though you replace the entire state, React will only update what changed, and 2) by using optimistic updating on the client (or whatever the proper term is), the user might not notice that the actual data-syncing is a bit slower. Plus, it'll still be faster than a server-side-only approach.
The nice thing is that sending the total state (of the page or component) every time significantly simplifies matters, to the point where you might be able to keep relying on your server-side framework for most of the logic, at least until you need to start optimizing stuff.
The big weakness of Angular is server side rendering,which involves heavy solutions like phantomjs,while you can render react components on the server.
Angular is not very good at rendering/managing svg either,that's a fact.
I would argue maintaining pure html templates is not that hard.
But frankly Angular solves so many problems these are minor issues.Writing complex lob applications is so easy with Angular I wouldnt want to use anything else.
The only case i'd switch back to backbone+react/vue/ractive and jquery is when i'm writing interactive experiences that are not CRUD apps.
So no,dont switch to React for the sake of switching especially since AngularJS just works. I mean people dont even bother learning javascript,they learn AngularJS ...
It has been discussed on HN before : https://news.ycombinator.com/item?id=7719957
Some good comments there, worth checking out. Personally, I think the message loop architecture proved very good in Windows when processors were slow and had only 1 core and it is at least worth giving it a try in web development.
Hence my question. I feel like for some apps I don't need 60% of what Angular has to offer (routing, controllers, modules etc.) I would be satisfied with just directives. Which are probably the part of Angular I like the least.
For SPAs I see no other alternative to Angular currently. In instances where I need heavy JS only on some pages, I'm not sure.
You could then incrementally add logic client-side to improve performance, if that's necessary (if the state object becomes too large, for example).
<my-svg-shape my-directive-that-mutate-svg-props />
doesnt work that well. Displaying SVG has never been a problem,they are like images. Unlike images they can be nested ,animated,modified at run time,scaled... if you think you can just create meta svg shapes with directives think again.The line in the post where "You can't even do something as basic as that with Web Components.":
var MyToolbar = require('shared-components/toolbar');
In fact has a direct analogue with HTML imports: <link rel="import" href="shared-components/toolbar.html">
And that's key to understanding Web Components. The idea of the standard is that you can now define your own custom HTML elements, and those elements function exactly like the DOM elements that are built into the browser. This is a key strategic point: they function exactly like the DOM elements that are built into the browser because Google/Mozilla/Opera/et al hope to build the popular ones into the browser eventually, just like we've gotten <input type=date> and <details>/<summary> based on common web usage patterns.A number of the other code samples in the article also have direct analogues in Polymer as well. For example, the App/Toolbar example halfway down the page would be this:
<polymer-element name="Toolbar" attributes="number">
<template>
<div>
<button value="increment" on-click="{{increment}}">
<button value="decrement" on-click="{{decrement}}">
</div>
</template>
<script>
Polymer('toolbar', {
number: 0,
increment: function() { this.number++; }
decrement: function() { this.number--; }
});
</script>
</polymer-element>
<polymer-element name="App">
<template>
<div>
<span>{{toolbar.number}}</span>
<Toolbar number=0 id="toolbar"></Toolbar>
</div>
</template>
<script>
Polymer('App', {
created: function() {
this.toolbar = this.$.toolbar;
}
});
</script>
</polymer-element>
You can decide for yourself whether you like that or you like the Bloop example more - my point with this post is to educate, not evangelize - but the key point is that you can define your own tags and elements just like regular DOM elements, give them behavior with Javascript, make them "smart" through data-binding so you don't have to manually wire up handlers, and then compose them like you would compose a manual HTML fragment.And the second you start doing conditional elements (like the tabbed example), Web Components gets pretty complex. In React, it's just `if(shown) { renderItem(); }`.
If you make HTML smart enough, sure, you don't have to manually wire up anything. But then you're left with `x-if`, `x-ajax`, and so on tags. Why not just use JavaScript?
As for scoping of imports, you do have a point there in theory, but in dealing with quite a few complex Polymer applications at this point I haven't seen that be an issue in practice. The scoping issue is well known among the people working on Web Components, and AFIAK there are plans to address it.
I'm not sure why you think conditionals are complex in templates. Your example might look like this in a Polymer template:
<template if="{{ shown }}>
<my-item></my-item>
</template>
Yes, there's some token overhead, but in the context of a larger template it pays off to have the entire HTML specified in one place, and in a way that mirrors it's output structure, not spread out over often hard to follow imperative code.However, as you point out, Web Components doesn't prescribe how to manipulate the DOM, so if you still prefer to do it in script, go ahead!
The point is to produce an element where the browser, developer tools, and your users don't have to care what choice you made.
When you start to bolt on features for dynamism in HTML you end up with Angular. The reason that it has all of those complex features is because it needs them to build real world apps. I'm sure once people have built more stuff with Polymer you'll start to see similar "feature creep".
I can think of very few common feature requests (mostly on Shadow DOM, actually), and they don't being to approach the complexity of Angular, which concerns itself with so much more than templating. Angular's complexity is not simply an unavoidable consequence of being used for real world apps - it's just complex.
To complete your C analogy - yes, C sucks a lot, and it's woefully incomplete in areas like namespacing and packaging. But people still use C, because if you want to do something native it's basically the only choice, and you know that it will interoperate with basically every other language out there. And those people have managed to build some pretty impressive things with C, warts and all, even though a lot of its design choices "will never work" when programming at scale.
In my ideal world, I want the performance of the Virtual DOM / rAF batching described in the blog post, I want web components as the underlying DOM / markup that represents my views, and I want to wrap them with Ember-like computed properties and routing structures. But hey, while we're asking for everything, I'd also like universal flexbox implementation, Clojure-to-asm.js compilers, ES6 generators to finally come out...
Actually that's factually inaccurate. You certainly can do that. registerElement returns a Constructor function, so you can export that in your module if you want to be able to require it elsewhere.
I was very confused about the Web Components criticism, it seemed like the author didn't understand Web Components at all. My first thought was, "Why would you want to import your element into JavaScript, unless you're going to be doings something scripty with it?"
What you really want to do in a custom elements world, is embrace HTML, as opposed to JS, as the place to build your DOM. Instead of:
Bloop.renderComponent(Box(), document.body);
do: <bloop-box></bloop-box>
Then I don't get this paragraph at all: > Aren't you tired of having to query the DOM tree and manually manage the structure do
> create UIs? Web Components doesn't solve this at all, it just tries to encapsulate the
> work. The problem is that building apps is building components, so you inevitably are
> forced back into the manual DOM management to create your app-specific components (like
> how you constantly have to create directives in Angular). You also need to jump into
> JavaScript to configure and wire up any Web Components you used. It's a very messy
> abstraction, and fools you into desiring a pure HTML-based declarative way to write
> apps, which like wanting steak but eating liver.
What?Of course the point of Web Components is to encapsulate the implementation DOM and the work of manipulating that DOM, and not prescribe how it's done, because you can do it in many ways: manually use DOM APIs, use templating like in Polymer, or even use React if you want.
The author then mixes criticisms of Angular with Web Components. Angular doesn't produce Web Components, has far too many complex concepts IMO (like the $scope.$apply example), and so far has rejected a Web Components centric approach (see their 2.0 design docs). You have to create many directives in Angular because it doesn't support standard 2-way data binding to properties out of the box: without directives you can only bind to attributes. Polymer, for instance, doesn't have those problems, and very complex widgets are built with templates.
And the complaint about needing JavaScript to configure Web Components seems to be completely without merit. Web Components imported with HTML imports are fully capable of registering themselves, so the import is all you need. Yes there's some JS under the hood, but you don't see it, and all of "Bloop" is JS anyway, so I'm really lost on this point.
React may be great, but the future is exactly in encapsulating away the work of building custom elements so that an application can be built of elements sourced from different vendors using whatever tools they want to implement them. I would have no problem using custom elements built with React, but at this point I am not interested in components that force me to use a particular framework. Trying to proclaim that all apps should be built with this or that awesome framework, is a quickly aging point of view.
The discussion here has led me to a few more things to research, but I feel it's been very helpful in helping me think critically about the vast array of possibilities a budding web designer has to deal with. I just wanted somebody to provide an objective view of "If you're going to be doing medium-complexity web apps end-to-end, then learn ______" and I still would love that, but don't think it's possible to get. The alternative, as I've been doing, is just to learn a little about everything, try to figure out the kind of things I plan to do, and then find the paradigm that works, be it vanilla technologies, something like React, Web Components, or a framework (and I've been trying to learn Angular and like it, but it's tough to grasp). It just seems like as soon as I've decided on what I want to learn, I read a new post with a title like "Why You Shouldn't Use <whatever I just decided to learn> and Why <something new I've never heard of> Is Really the Way to Go."
So anyways, a long-winded thanks, but a thank you nevertheless for the open discussion here; I feel better now that I'm not trying to find the one-and-done "best" thing for making web apps in general.
I plan to expand it with a toolkit to allow thinking in terms of batches, queues and consumers, à la bacon.js[2].
[1]: https://github.com/zenoamaro/honeyloops [2]: https://github.com/baconjs/bacon.js
Example: in Chaplin, components are views or subviews (because it's still an MVC framework, which is another discussion for another time). The views by default render automatically without you having to call anything. But if you did, you'd write @render() (because hey, Coffeescript saves keystrokes and sanity). That automatically renders the component in the place you've already specified as its container attribute, or if you haven't it renders to the body by default.
Whereas in React, you have to write this garbage: Bloop.renderComponent(Box(), document.body);
WHY. Can't we write a framework that intuits some of this crap? Shouldn't we use a framework that reduces the time we spend writing code?
Comparing this.render to Bloop.renderComponent is superficial. If rendering needs to have a handle on different resources, you'd either violate the encapsulation in the former example, or write a service to couple them on a separate layer -- that service might as well be called Bloop.
Some of this crap makes hard things possible.
Great read, by the way.
Since React claims to be super fact, has done a performance comparison to see in what situations and how much better react performs in certain cases, compared to say, angular.js or more vanilla frameworks?
(Also I hear that there is a really great speedup that using OM gives you, but I haven't seen any comparisons with om either)
there is so much overhead with these solutions performances would just be bad.
However it would be interesting to extract the virtual DOM from React to use it in the context DOM based games, being able to mark elements as dirty in order to redraw them is a usefull feature.One just doesnt need all the JSX/databinindg stuff for a game driven by a gameloop.
(Wolfenstein Rendering Engine Ported to React)
https://github.com/epeli/node-hbsfy https://github.com/rotundasoftware/nunjucksify
Developer: Hmm...I wonder how long it's going to take me to figure out where that HTML was generated in my javascript.
http://facebook.github.io/react/blog/2014/01/02/react-chrome...
You can either build something on a mass production line, where you're just screwing the same bolt in day in and day out, or become a master craftsman and build it with proper care, design, and quality.
These frameworks are nothing more than a factory floor and if all you do is build apps with a framework you're little more than a paid glue stick piecing bits of code together. Or you can become a master software developer and build something of quality without needing a crutch like a framework.
Now, if the needs of the project are such that a framework will suffice then by all means, use a framework. Chances are, if you're doing more than building a working prototype then at some point a framework is going to fail you. If you enjoy building apps using frameworks then by all means, do it. But to my mind you're doing your customer a disservice.
Contrast that with great software developers (and I've been fortunate to have worked with some really great developers) who abhor these frameworks. They can get more done with less code and ultimately deliver the project faster without frameworks. The tradeoff is that it takes time and dedication to achieve that level of mastery. I personally would prefer that path.
I don't know who pointed it out, but I find that a good rule of thumb is to master at least one layer of abstraction below the 'current' one. So in the case of React, you'd first make sure you are proficient with javascript, the DOM, and how the web works.
If your point is to underline that using frameworks without understanding them is a bad thing, I fully agree. But arguing that 'these things' (frameworks) are bad just seems silly.
Clearly some clever people at Facebook found it useful to abstract certain things in a certain way, and many other people (some clever) like their approach. They've actively considered IanDrake's problem (in fact, they talk about this in their talk on React), and felt that their solution was good.
If I can build a performant client-side-heavy web-app in half the time because of React, I'm doing the client a service, not a disservice.
They're really good at getting you to 80% completion really fast. The next 10% takes a little work but its doable. But that last 10%... its like pulling teeth. With tweezers. Covered in grease.
That last 10% is the thing you need done to successfully deliver the project but which the framework designers didn't consider.
In my experience you always run into that last 10%. The net result is that all those speed gains you realized early on are completely lost (and then some) because you're fighting with the framework.
So sure, understanding the framework might help you with that last 10%. But I personally think you're better served mastering JS, the DOM, and how the web works. Which really isn't that hard by the way!
And anyway, if frameworks were so great why are there so many? It seems like a new framework gets announced every week here on HN. The shear tonnage of frameworks alone makes me question their value[1].
Now if none of that can convince you, consider this; the company I work for got rid of all their framework programmers and replaced them with me and a couple other software developers who have experience building products without using frameworks. And they pay us more money than they paid the framework programmers. Why? Because we did more work with better quality in the first six months than those other guys could do in 2 years of gluing framework code together. That last 10% hit them HARD and cost them their damn jobs!
1: I do recognize that frameworks provide value. My argument is that they are way overused. Great for building working or semi-working prototypes in order to test an idea in the market. Terrible for building anything that needs to be continuously maintained.
Just raw DOM manipulations?
I feel like your argument is partially valid, but your argument also sounds like it effectively argues for pure Assembly. Anything ontop of that costs you a ton at the 10% mark. Now, i understand there's a difference between a Framework and a Language, but i hope you can understand my point.
I feel like you're going to one extreme, and arguing against another. Arguing opinionated frameworks with equal opinionated design seems odd to me.
Lastly, what are your thoughts on code maintenance? I feel like there is something to be said for "Get it done" thinking and "Make it maintainable", and sometimes they don't see eye-to-eye.
If it's cleanly written, with a framework that makes sense, isn't it far easier to maintain than raw JS? (Not specifically about React, just in general)
Disclaimer: I like React quite a bit. But i don't think you're "wrong", we just see things differently.
Lastly, what are your thoughts on code maintenance? I feel like there is something to be said for "Get it done" thinking and "Make it maintainable", and sometimes they don't see eye-to-eye.
You're right, they don't always see eye-to-eye. Frameworks are handy if you need to "get it done". You also need to educate your customer that you will have to make trade-offs and cut corners when trying to just "get it done". But I also argue that with enough experience you can, in fact, get it done and make it maintainable. I've seen that time and again.The reason I don't believe you can write something cleanly with a framework and it be easier to maintain is that the framework is a black box of unknowns. So one option, as someone else has mentioned, is to try to fully understand that black box. But then you've just tied yourself to that framework. Wouldn't you be better served mastering the technology that the framework is written in?
1: jQuery proper. jQueryUI isn't too bad but is still a little more black box than I prefer. I really dislike jQuery Mobile for all the reasons I dislike frameworks.
The result of all this is code that is harder to maintain, even for those who know how to use said framework.
While I'm not against frameworks myself (in fact I argued in favor of them in this very conversation), I have become much more weary of them. In fact, after a brief affair with CoffeeScript I've even come to be more hesitant about using that or other 'transpilers', as I recently ran into the problem where I had to revert to plain js and I discovered that I'd lost some proficiency.
That said, it depends partly on the developers, and partly on the amount of structure the framework forces you into.
And that said, I suspect using a framework often serves more to alleviate managers' concern about maintainability than anything else.
There's one case where I would strongly suggest someone use a framework though, especially an opinionated one such as Rails. By following the Rails Tutorial by Michael Hartl, I learned a lot about best practices that I wouldn't have learned had I cobbled together a bunch of libraries. So for beginning developers, a framework might help them get started with their prototypes and whatnot.
Then again, maybe that worked for me because I can't help but want to look behind the curtain... I've certainly met my share of developers who never seen to wonder what's behind the magic.
Last year I got excited about NodeJS and started working with it quite heavily. Then I started to see holes - difficult debugging, so-so tooling for development, mixed bag of JS components, and so on. I then stepped back and realized that although it was interesting, and I can see it useful for some specialized server-side development, I don't see it as compellingly different than current alternatives (Rails, .NET, PHP, etc) to try to build a whole web app with it.
To extend your argument, I would state that frameworks are only about speeding up the initial creation of an application that fits into a narrow set of assumptions. Frameworks, by their very nature, capture a set of decisions by their designers about how an app should work (or behave). As long as your app fits nicely into this box and you can live with the downstream risk that maybe it won't one day, then go for it.
I took issue mostly with the blanket statement that frameworks are bad, because I think there's a lot of variety. Backbone, for example, is so basic that it might be useful for 'master' programmers, whereas Rails is a monster framework that is a bitch to handle if you get to that 10%. And I'd argue React, which is more of a library, could be a very useful abstraction that leaves you free to do things your own way, or even replace it eventually. But I might be wrong about that! I'm not a master...
Also, I guess in the context of the framework/library-explosion it makes sense that you'd point out the problems with a little less nuance :). And it's a good reminder for me as a young framework-raised, self-taught whipper-snapper to make sure I become a master at my 'craft'.
And not just because it pays better.
If your average LOC is ever more than 200 lines or so, you've got a messy app.
Ranting against frameworks represented by React is a strawman here. It doesn't include a router, nor a model layer, nor the traditional controller. It's a miracle that it's even compared to Angular and Ember, but I guess that's the extent of the power of View + solid declarative nature, so we'll take it as a compliment.
We also don't want to turn it into a huge framework, so if that's your only concern here, then please feel free to give it a try =).
The trick is to understand the strengths and weaknesses of any given framework and match those with the constraints of your project.
Things like jQuery and Underscore on down to stdio.h are libraries. You can pick and choose from what they contain but they're not so tightly coupled that they get in your way.
They're a tool belt with tools that do one thing and do it really well. Frameworks are like having a tool belt with a hammer that also has a saw on the end but in order to use the saw you have to grab the screwdriver even if you're not actually using it.
That said, React is a "A Javascript Library for Building User Interfaces." And to me me it does feel more like a library than a framework.
It takes your data as an input and by some mechanism lays out a visual representation of it defined by your components render methods, being sure to update the visual representation as the data changes. The rest are implementation details.
Full stop right there and you're correct. I really prefer to limit code that looks like:
element.innerHTML = '<div>Do you really like content in your JS like this?<div>';
I'd rather have the HTML loaded as one file and have the javascript in another acting on that HTML. Right now my favorite library to use for this is Knockoutjs.I thought one of the cardinal sins of web design was don't break the back button.
I just wanted a way to put templates in <script> tags that get loaded by React Components. That way, I won't be mixing templates and the behavior of the components. Has anyone done this before?
But really, once you get used to keeping everything together it really does feel better. You just have to try it out.
Personally, since I use CoffeeScript, I like this lib:
https://github.com/atom/reactionary
which, since it strips out the required `null` or `{}` first parameter, feels very much like haml or jade.
I think I'm slowly being convinced putting it together in the same file makes sense, since it's a single component, and the what's being displayed is coupled with what you'd do with it, so I guess it should belong in the same place?
Something like this:
React.createClass
render: ->
{div, h1, span} = require 'reactionary'
div class: 'home',
h1 "Hows it going!"
Clean and simple, particularly with CoffeeScripts default return.As far as templates go -- and this is what I always tell people -- structure your code in a clean way which makes the render function pop out and you might as well be working with a separate file! It really does make more sense after a while.
I checked out reactionary, why couldn't I just do:
{div, h1, span} = React.DOM?
- Placing markup and logic in separate places separates languages, not concerns
- React/JSX has the full power of JavaScript, not some intentionally crippled lookalike
Using a non-common ui idiom is risky. The presentation and topic don't match in a way that reader (i.e. me) had enough expectations left when it comes to what you might actually have to say.
On the other hand, I actually found the content pretty great, but I'm not a web developer so take that with a grain of salt...
P.S. I haven't looked into this in depth, just throwing an idea out there.
Similar techniques have been used in other types of programs where performance is critical - for instance, user mode networking and user-mode thread scheduling can be quicker than the kernel-mode equivalent because it reduces or eliminates expensive system calls.
From what I understand, the core idea is that changes are applied to the virtual DOM in a very simple way (from the application point of view). Then there is another piece of code that knows how to efficiently find the diff between the vDOM and DOM and apply the changes. It seems that last part could be done by the browser.
Would you model the drag in the main data model somehow? Or would you do that all externally (with traditional DOM manipulation) and then update the model when the drag is complete?
Check out http://webcloud.se/sortable-list-component-react-js/
All that ends up happening in practice is untested, messy code with deadlines up your ass and 0 developer ergonomics. Zero.
All those things are cool for social apps (a.k.a. fart apps) but for business ready platforms this is just silly.
for example, a link that i can middle click or bookmark or send to someone, etc would be much more useful even if not as spiffy as those scrolls
edit: HTML/next apparently: http://www.w3.org/wiki/HTML/next