
Reactive UIs with React and Bacon - nullobject
http://joshbassett.info/2014/reactive-uis-with-react-and-bacon/
======
diziet
Maybe 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.

~~~
lomnakkus
Knockout 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
I 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
Angular 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.

------
davedx
"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
My 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/)

~~~
camus2
> I understand why people still use e.g. Angular, > but only for the same
> reason as why people still use PHP: legacy.

Not an Angular lover, but devs use Angular because it's the quickest way to
build LOB clients with javascript. It's no legacy or whatever,just pragmatism.
People coming from flex/wpf know what I mean.

Angular doesnt answer all problems and is not for all use cases but for LOB
clients it handles 90% of use cases and problems. Same cannot be said for
React without 3rd party libraries.

No framework can ever be a silverbullet, I would not use Angular for an app
with a lot of transitional states and animations.

In theory you could use React with Angular but frankly I dont see the point.

> but only for the same reason as why people still use PHP: legacy

? You just cant compare apples and oranges, a javascript framework and a
serverside scripting language.

~~~
danford
Angularjs first release was about 6 years ago so it's hardly legacy. It's
almost as if the OP was trying to plug React..

Anyway, in my experience angular is half the code, half the time, and half the
cost.

[http://www.google.com/trends/explore#q=Angularjs](http://www.google.com/trends/explore#q=Angularjs)

Well will you look at that, angular seems to never get less popular.

------
dangoor
The 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
I 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.

------
dreamdu5t
Am 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.

------
Kequc
All 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"

~~~
asolove
Ok 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.

~~~
Kequc
Build a javascript object.

    
    
      MyApp.CatManager =
    
        init: ->
    
          @container = $('#cats')
          @collection = {}
    
        add: (cat) ->
    
          @collection[cat.data.id] = cat
          @container.append cat.element
    
        remove: (cat) ->
    
          delete @collection[cat.data.id]
          cat.element.remove()
    
        all: ->
    
          $.map @collection, (cat) -> cat
    
        get: (id) ->
    
          @collection[id]
    
        arrange: ->
    
          sorted = @all().sort (oa, ob) ->
            a = ob.data.name
            b = oa.data.name
            if (a < b) then -1 else if (a > b) then 1 else 0
    
          $.each sorted, (i, cat) =>
            @container.append cat.element
            true
    

Allows you to maintain full control over configuration and of what is going
on. I have a question, Angular was built by very smart people at Google that
is undeniable. But, does Google use Angular in their products?

I think that if the application needs to be sufficiently complex and the
complexity maps to exactly what an existing framework does then you should use
the framework that it fits.

Generally often does that happen?

~~~
asolove
This implementation will be incredibly slow for large lists. Every time any
one of the elements moves, you will make N dom changes rather than the needed
one or two. In an individual case, you can hand-write the faster version. But
when you have multiple components like this interacting, knowing how to do a
minimal change is not an easy task.

Unless you have experts writing these things by hand, using a framework is the
quickest way to minimize performance problems and memory leaks.

------
ehutch79
Are 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.

------
lightblade
A 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.

------
jbeja
I 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.

------
susi22
There 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)

------
j_s
Thanks 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
React 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.

