6 ms·
Reactive UIs with React and Bacon
- diziet 12y agoMaybe I am not getting it, but to me react.js seems like a bad way of wrapping your view html in javascript. What can you do easier using react.js (and backbone) that you can't already do using knockout and plain html or whatever markup you prefer? To me, there is a reason to abstract javascript and similar logic outside the plain html -- however the workflow of including script sources inside html that in turn include html that gets rendered is backwards.
- catshirt 12y agothe reason your html is modeled at the javascript level is because of the DOM efficiencies it provides. but they've provided JSX on top which means you can essentially write "plain html" as with any other application. i really prefer having my template and it's logic in the same language. one option is React without JSX, another is clojurescript. the short answer to your question is that Backbone and Knockout (afaik) don't do diffs to update your DOM.
- RussianCow 12y agoThat's not particularly relevant because Knockout doesn't need to do diffs--it uses the observable pattern, so in most cases it knows what changes have been made the moment they are made.
- lomnakkus 12y agoKnockout is pretty good, but the big deal about React vs. Knockout is components and the reusability you (can) get from componentizing your view code/html. This is something that you might not notice (and it might not even be relevant) if you just need to drizzle a little Knockout throughout your app/site for a little interactivity, but the lack of abstraction really starts to hurt once you go beyond simple interaction. EDIT: Oh, I should also mention the Virtual DOM, but that's not really that relevant unless you're experiencing performance problems. It might also be very handy for server-side rendering, but I don't have actual experience with that, so YMMV.
- mandeepj 12y agoI think angularjs is better than knockout if u r looking for full blown mvc app in Js as it supports DI and testability. On the downside, angularjs have lot of configuration
- paultannenbaum 12y agoAngular is a framework, knockout and react are data binding libraries. You can get dependency injection and testing with both, its just something you have to set up yourself.
- baddox 12y agoIt seems to me that Knockout's custom bindings provide the same reusability as React. The only difference I see is that React recommends their JSX preprocessor to allow HTML right in the JS, whereas Knockout custom bindings require building elements using the JS DOM API or hooking up some preprocessor manually.
- lomnakkus 12y agoCustom bindings which generate DOM get you some of the way, but not quite the whole way. One of the disadvantages with custom bindings is that they are rather tightly bound to how the view model looks. If your binding expects something which isn't directly in your view model (at the right level) and perhaps requires a little transformation of your view model, you sometimes end up adding "synthetic" computed observables just to transform from your real view model to the view model that the custom binding expects. This is not really encapsulated very well. (I hope that makes sense, it's kind of hard for me to explain.) In React it's just simple JS which you write exactly where you need it, namely where you instantiate your component -- it doesn't even have to escape the scope (vs. KO where it "pollutes" the view model in the "owning" component so to speak). EDIT: A little addendum: It's been a while since I've used KO in any serious way, but another issue is that of embedding arbitrary components inside another. One thing is generating DOM from whole cloth, but if I have a component which just takes other components as input then the KO model breaks down.
- antris 12y ago> To me, there is a reason to abstract javascript and similar logic outside the plain html -- however the workflow of including script sources inside html that in turn include html that gets rendered is backwards Yes, coming from a traditional JavaScript MVC background it's hard to let go of this idea, when it's been touted everywhere for years. But the fact is, there's no fundamental reason why we need to put these technologies into separate containers. I recommend this talk by Pete Hunt: https://www.youtube.com/watch?v=x7cQ3mrcKaY https://www.youtube.com/watch?v=x7cQ3mrcKaY edit. oops, linked the wrong talk
- ludwigvan 12y agoThe big idea is the render function in React describes your UI at any point in time. Not initially only, at any point in time. The biggest complexity in frontend development is that there is too much state. Most people, when doing frontend dev blame JavaScript for the difficulty. JavaScript is a problem, but it is not the problem. The problem is the management of state. Compare this to server side development. It is much more robust. Why is that? Because there is too little state, what you render has a little lifetime. Request comes, response generated, there you go. What's the problem with frontend? The app there has a much higher life. You get the page, interact with this, many interactions later, you accumulate state, but you are still dealing with the same "response". Hence the difficulty of building UI's. So, what's the solution to this? One: you need to manage your state properly. Two: through this state, you need to be able to define your UI at any point in time. Assume you solved these problems, but naively, that is, once state changes, you re-render the whole response. This would be much less bug prone. But now you have a performance problem: Changing state will not necessarily change all the UI response. Hence the genius of React's virtual DOM, which acts an intermediary, diffs the different responses over time, and redraw only what's necessary to redraw, not the whole UI response.
- baddox 12y agoKnockout templates also represent your UI at any point in time. The only significant difference as far as I can tell is that React feels strongly that pure JavaScript (with an optional preprocessor that lets you type HTML in your JS) is a better way to organize UI code than templates with bindings. With Knockout custom bindings, this difference becomes much smaller.
- peterhunt 12y agoI had to cut the Knockout-specific slides, but I do cover this topic in depth here: https://www.youtube.com/watch?v=h3KksH8gfcQ https://www.youtube.com/watch?v=h3KksH8gfcQ tl;dr it's about expressiveness
- ufo 12y agoI found the presentation really interesting.If I had to give a slightly larger TLDR the two main points I got from it were 1) In a virtual DOM system your view code is a black box, while in an observable-based system you need a way to specify all the data bindings. This means that virtual DOM systems can use usual Javascript abstractions (functions, varuiables, etc) where observable systems often need custom DSLs (for templating, data-binding, etc). Additionally, data binding can be tricky to get right when it gets more complicated, for example, if you have a sorted list of items it needs a way to know that should be rerendered when the inner properties change. 2) Performance: in a observable-based system, the memory and CPU costs are related to the size of the model while in a virtual DOM system the costs are related to the size of the view. This can be a performance gain for the virtual DOM if you have a big model but use windowing to display only part of it. Also, the O(n) cost on the size of the view is usually not a problem since views tend to be small enough that that fits inside one repaint frame.
- noname123 12y agoI think you're pulling more concerns about integration with existing JS MVC frameworks (e.g., Backbone/Ember/Angular) than just reacting. The Reactor pattern came more out of the back-end world where suppose you have a data stream that you have to filter and do more processing to create more data stream (e.g., person A,B post cat gifs on Wall on client -> pushed to respective the Facebook Wall stream for person A, B -> piped to Facebook Feed for person C who is subscribed to [A,B] -> combined with Facebook real-time ad-stream for demographics group X that person C belongs to -> pushes the ad-infested social media crap down to the user C on client), Now normally all of these would be traditionally done via a HTTP RESTful Ajax pull request from the client-side and the back-end service would query the database or some kind of caching service (Redis/Memcache) and perform some application logic to combine the data and send it down to the client-side. Reactor pattern tries to do away with the service layer and instead have the JS clients as first class citizen subscribers in a publish-subscribe model and pushes the streams of data down to the client. So you can think of some really exciting use-cases, like Pornhub/Youtube/Spotify processing streams of everyone who is watching a video at any given moment; then showing everyone the chain of top "branching-off" of video's that everyone is watching and have the people who have this shared "experience" chat and lead the group to the next recommended video and so forth for a much more collaborative and real-time media consumption/"discovery" experience.
- spyder 12y agoKnockout too pollutes the HTML with it's own "language" in the "data-bind" attribute (for example: data-bind='value: itemToAdd, valueUpdate: "afterkeydown"') True separation would be if there will be the HTML file and then there will be a separate definition for the data bindings using selectors, because then you don't have to touch the HTML when you change bindings. React cannot do that but the other useful feature i was looking for is that it can render the views on the server-side (node.js) too.
- diziet 12y agoSure, though I'd argue that knockut's data-bind attribute makes sense to fit inside HTML as it makes any sort of debugging a lot more straightforward (with the exception of handling context and what hierarchy your specific model is in at this very moment).
- davedx 12y ago"Perhaps this example is a little too contrived, but the real power of reactive streams becomes apparent when you want to do something more complex." What is that something? This is indeed a recurrent problem with all these new tools and technologies: small examples that don't reveal the issues you will have when your system starts to get larger and more complex.
- skrebbel 12y agoMy team has been using React full time since half January. What felt like a gamble initially, turned into mad love. I understand why people still use e.g. Angular, but only for the same reason as why people still use PHP: legacy. React is simply that much better. I hope its ideas will spawn many followers. Our design/css/markup person loves it, because with JSX she can trivially write familiar HTML, and at the same time she's highly encouraged to make little reusable building blocks (components, in React lingo). The result is that our view codebase is remarkably well structured, even though very little of it has been touched by seasoned hardcore programmer types. React pulls us into this "pit of success" of locality, reusability and clarity. I'll braindump what we do, for those interested, just to share an alternative approach as the one listed in this blog. I'm not sure whether it's better or worse - we're probably doing some things in ways that could be better, so I'm very open to questions and critique, too. Our frontend architecture is Model-View-Nothing. Our view is pure React components, with a root component called View which has, as its state, the current page and the model. We also have a thin "proxy" with a function for each backend API call, but it has no state so it's not very interesting in terms of architecture. The model is a simple hierarchy of classes. We use TypeScript for these classes, but it could've been CoffeeScript, ES6 or JS-hacked classes as well, no difference. Our root model class owns all other model objects, hierarchically. A user action typically causes our model to want to extend or update itself. It does API requests to our backend for this. In the case of PUT/POST/DELETE, we update the local model first, and then asynchronously send it to the server - our data is such that we can assume that most of the time, the operation will succeed. This is great, because we can re-render the view before the server even acknowledges the operation's success. This makes the app is very snappy. We even do the same with GET requests: very often, we already have some of the data we're getting (e.g. if you go to a user profile, you typically clicked a link with that user's name and avatar on it). When it makes sense, we just show the page immediately with what data we have, and show a little loading animation for the rest. Again, this makes the application feel very responsive. This works for us without any additional tools, because our model layer somewhat resembles the structure of the view. I suspect that this is quite common (e.g. if you're displaying a list of tweets by a user, you probably have a "root -> user -> list-of-tweets" structure both in the model and the view). It allows us to pass only the model data to a React component that it needs, making our React components very slim and reusable. In effect, our model layer is one big client-side cache. The methods on the model deal with synchronizing this cache, and the view just re-renders whenever the model tells it to. Another benefit is that if users navigate to pages they've seen recently, we still have all the data, and can show it right away (and refresh it in the background). All of this works great on mobile too. Especially when viewing a page you saw before (e.g. by hitting "back"), the difference is enormous: many mobile browsers cache very little history (at least my Chrome doesn't do it much), but for our page, it's instantly there. We would've gone for this dynamic no matter what, because we want to make a web app that feels like a native app. Nevertheless, I believe that React allowed us to do it with amazing simplicity and effectiveness. Other tools, such as Spine[0] encourage the same asynchronous dynamic, but I believe that without React, we would've spent a lot more time fighting with state, asynch timing issues, and all that. [0] http://spinejs.com/ http://spinejs.com/
- Kequc 12y agoAll of this complex front end framework stuff I really don't see that it is necessary. You can write basically the most important part of the framework into a very small coffeescript file. https://gist.github.com/Kequc/11083050 https://gist.github.com/Kequc/11083050 Then your class: class MyApp.Cat constructor: (data) -> @element = $('<div class="cat"></div>') @update = new MyApp.Update @, name: (v) => @element.text v color: (v) => @element.css backgroundColor: v @update.all data new MyApp.Cat name: "Gary" color: "#FF00FF"
- camus2 12y agoWriting an observer class in easy, Managing the state of hundreds of them is not. Now what if the user can change the cat's name by clicking on it and editing the div content,but cant give a cat a name already taken, because this cat is part of a collection of cats on that web page, which have the same editing features as Gary? Of course, cats are sorted and any change to one cat updates the sort order. Suddenly your 39 line framework becomes worthless.
- Kequc 12y agoI am presuming that the application stores its state server side, if that is the case than this is not at all useless. Presumably you are sending the edited name to the server the server sends back the result of the edit. If the result of the edit was that the name was unavailable and therefore remains unchanged then this won't do anything: gary.update.all jsonResult Even if you aren't storing state server-side. In the update attr methods have name changing check the rest of your cats for an existing name.
- asolove 12y agoOk now let's try to write a Todo List app. We'll have a TodoListView that shows a set of TodoViews. The TodoListView will need to initialize instances of TodoView for each item in the list, and react to model change events to know when to create or destroy new child views, so somewhere we'll need a map from model id to TodoItem view to do the book-keeping and cleanup. The child views will be displayed in order based on one of the model attributes, so whenever that attribute changes on a model, we'll need to find the relevant views and manually reorder them in the dom. And what happens when something in the todo item changes: do we re-render the whole thing (don't double-attach event listeners!) or selectively change individual parts of the dom? If you've built large-ish things manually or with Backbone, as I have, this kind of thing is about 80% of your code. Just doing bookkeeping and manually futzing around to keep the dom in sync with your data. Now compare with React, Angular, or Ember. Your list view just says: take all my todos, order them, and display each one in this way. It's the framework's job to deal with creating and destroying, reordering, and updating those views in order to keep the DOM in sync. This ends up cutting out lots of code while producing better results, since the framework is written by smart people and thoroughly tested, whereas ad-hoc list view implementations are generally either buggy or have memory leaks.
- jbeja 12y agoI love how Reactjs is getting more and more popular, i was yearning for something of quality to reach the top in the js world this days, and React seems like a very good competitor. And what i like most of it, is as simple as jQuery.
- ehutch79 12y agoAre you required to mix coffeescript and plain javascript like that? What's the advantages to writing half your app in js and half in coffee script? at least it isn't half coffeescript half typescript this time.
- susi22 12y agoThere is also a todomvc with undo using baconjs. It's pretty neat when you can use Bacon model: https://github.com/hura/todomvc-react-baconjs https://github.com/hura/todomvc-react-baconjs
- dangoor 12y agoThe use of setState in React strikes me as a code smell. React has two ways to provide state for components: props and state. I prefer using React in a more functional style: your model is managed separate from the view and updates are handled just by re-rendering the view from the top (which React handles efficiently). In other words: I haven't really seen a need for a library like Bacon when using React, because React provides a means for generating a view without "wiring it up" as you do in a typical reactive app. You just regenerate the view whenever an action is taken that might have changed the model.
- williamcotton 12y agoI agree. Using setState within a nested component should be limited to UI-only functionality, such as tab views or toggling menus or the like. Even then, if one were to have a single object that store the entire state of the application, this object could easily be saved to localStorage or pushed to the network for syncing to other clients. If the user were to reload the application or perhaps resume use on another device, they would be presented with exactly what they left behind. The infrastructure and code to do so would be very trivial. The days of state being spread over and managed by a number of objects has come to an end, at least for me.
- lightblade 12y agoA lot of this is over kill. FRP has a lot of complexity overhead before things get easier. For task like simple data binding as shown by author, your regular data binding library (angular, knockout) is enough. Doing the same with Bacon only makes it more complex. FRP only starts to excel when you need to weave multiple signal sources together. Examples includes key combination for certain hot key. Or signal switching when implementing drag and drop.
- j_s 12y agoThanks to so many sharing their experience here. I am considering using React but am stuck supporting IE7(!). Can anyone share their practical experience using React with clunky browsers?
- peterhunt 12y agoReact is ie8+. I think it could be made to work on 7 fairly easily, we just didn't need it for FB so we never tested it.
- dreamdu5t 12y agoAm I the only one frustrated by the seeming lack of communication and mindshare between devs working on React and those working on Web Components (polymer.js). There's so much overlap yet I can't find a detailed comparison or discussion of the two directions. The mailing list discussions I've found the devs seem very dismissive of each others projects.