
Application Architecture with React: Rethinking Flux - dgellow
http://dialelo.github.io/application-architecture-with-react-rethinking-flux.html
======
davedx
Always good to see alternatives to "Flux classic" [1].

We have just started using Redux [2] with ImmutableJS. It's a nice way of
expressing how different actions mutate the store, but I do feel like there's
some leaky abstractions in there - e.g. ImmutableJS is usually used for
performance reasons, yet you see your entire app filled with getter
boilerplate to get the data from the immutable structures.

I have to say I don't quite see the difference between CSP used here and
normal eventemitter style code. Can someone explain the difference?

[1] [https://github.com/facebook/flux](https://github.com/facebook/flux)

[2] [https://github.com/rackt/redux](https://github.com/rackt/redux)

~~~
foxhedgehog
I thought that the reason for immutability wasn't so much for performance as
much as for getting predictable state to enable time-travel, etc.

~~~
masklinn
It's performance wrt state invalidation for work skipping. The library can
check the state tree, and if the tree (or subtree) has not changed skip
rendering entirely. With mutable state limited assumptions can be made so by
default you have to render to vdom and diff that.

With immutable state you can do an identity check on the current state node
(pretty much free), and only perform the render if it fails. On specific
components you may want to go further and do a deeper equality check if the
identity check fails (if rendering is expensive) but immutable collections
generally give a lot of bang for your buck when it comes to skipping state ->
vdom.

~~~
guscost
I've actually used a plain state object with UUID version tags saved at each
node that needs to be optimized. Whenever the store updates that node, it also
updates the version tag with a new UUID. Then shouldComponentUpdate just
checks whether the version tag is different before rendering.

For my purposes this optimizes at least as well as ImmutableJS, and there is
no overhead from loading and using a dedicated library. However it does
require extra boilerplate and manual updates to version tags each time
something changes, and it can cause confusion if you forget to update a
version tag or accidentally update the wrong one. Anyway, it is one
alternative, but if you don't have a compelling reason not to use ImmutableJS
for optimization I'd probably go with that. Of course it is perfect for
undo/redo functionality too if that is a requirement.

~~~
rymohr
Your approach sounds interesting. Ever write about it?

The undo / redo gains of ImmutableJS quickly vanish when you're working with
remote data and the leaked getters aren't fun. A little UUID juggling is worth
it if it allows my components/reducers to work with plain old javascript
objects and still get fast shouldComponentUpdates.

~~~
guscost
It's one of the ideas for shouldComponentUpdate that I wrote about here, but
it's not described in a lot of detail:

[http://guscost.com/2015/05/27/react-js-and-flux-ideas-for-
pr...](http://guscost.com/2015/05/27/react-js-and-flux-ideas-for-practical-
applications/)

One of these days I'll put up another piece on Flux/React, and an example
application to demonstrate an approach that doesn't have a lot of dependencies
(not even ES6, for example).

Also I have not run into any pitfalls using ImmutableJS yet apart from the
extra overhead, so thanks for the heads up.

------
gedy
Maybe it's just my peers :-) but this highlights to me why I've been reluctant
to adopt React. I keep getting eye rolls about not using it - but everyone I
encounter seems to in the process of still figuring out application and
architecture basics? We weren't an Angular shop, so never had the problems
that React seems to target with one-way, etc.

~~~
grandalf
It takes a while to get a sense of appropriate component boundaries. Like
other decisions, this involves tradeoffs.

I've found that I sometimes err in the direction of making components too
granular, when this makes the data flows more complex.

Boundaries should exist for encapsulation, but also for change management,
reusability, and interfacing with data.

Yes, components can be misused.

I've found that codebases such as rails apps often have so much boilerplate
and blind following of conventions (equating to many, many lines of code) that
the more fundamental issues like flawed domain modeling or incorrect
abstractions are rarely even considered a problem.

~~~
gedy
Yes true, and to be clear, I think React is fine on it's own. It's just that
from my view it's not fundamentally so superior as to warrant rewriting a
decently structured app written in one of the other JS frameworks from the
past few years. Especially if folks then go and have to reinvent/relearn,
well, everything.

A lot of "React" excitement folks shared with me had more to do with using
Webpack and ES6, which you can use with other frameworks.

~~~
grandalf
I think this is true. One should always very carefully consider the notion
that a rewrite is a good idea.

------
masklinn
> Om solves this problem with an abstraction called Cursor, which lets us
> focus on a path of the global atom and offer the same API as atoms. This
> allows views to treat the substructure as their data source and even modify
> it with the same operations as the Atom. I wrote a simple implementation of
> this concept for using it with atoms and immutable data.

FWIW Om Next moves away from cursors and towards something closer to
GraphQL/Relay queries.

~~~
dustingetz
> Om Next moves away from cursors and towards something closer to
> GraphQL/Relay queries.

Can you elaborate, I watched the Om Next talk i think you're referencing and
recall David saying this, but I do not really understand why or what Cursors
have to do with GraphQL/Relay as they are separate concerns. (Cursors are a
way to update deeply nested data structures and don't do I/O, GraphQL and
Relay are ways to coordinate/sync state from backend to frontend and involve
I/O.

~~~
drcode
Both cursors and Relay involve syncing a "database" to a declarative view
object- In Om Next, there will be a new query language that maps the database
to the views, so it can be used both for in-browser data (like cursors) and
server data (like Relay).

What makes Om Next special (or so is the hope, very little specifics are
available yet, but the author that makes these claims has a stellar
reputation) is that the query syntax gracefully handles component composition
and removes a lot of the "magic" of maintaining reliable link with data
residing on the server.

~~~
dustingetz
> Both cursors and Relay involve syncing a "database" to a declarative view
> object

A cursor is something that implements the atom interface, and refine [1]. What
does this have to do with databases and declarative view objects?

It would make sense if GraphQL/Relay were used to sync backend state to
browser state, and then cursors are used to sync browser state to a view, but
here, cursors are still part of the picture! Or is it that components will
directly sync with the server, so no mechanism to sync browser-state to a view
is necessary? What about application/UI state that doesn't exist on a server?

[1] From the OM wiki:

" _In Om, you keep all your application state in a single atom (the root
atom). Components, however, generally do not care about the entire scope of
the application state, but focus on specific parts of it.

"Cursors are Om's way to manage a component's focus on just the state data
that it needs to operate. Cursors split one big mutable atom into smaller sub-
atoms that remain in-sync with the state held in the root atom. Cursors keep a
path to the data within the root atom that the component needs to deal with.
Sub-cursors are produced by refining the path._"

~~~
drcode
> What does this have to do with databases and declarative view objects?

Well, you can think of a cursor as a query into the state, with support for
dependency tracking. I think your confusion is that you're asking "How is what
you're describing like a cursor?" when I'm saying "Om Next is going to replace
cursors with something very different."

...so you're right, it isn't the same as a cursor anymore, because swannodette
is moving away from the cursor paradigm into more of a "querying" approach.

------
alexro
With each next article about React (and more generally javascript) it's more
apparent that the final result is a mongo/rethink like db in the front-end
with a transparent sync to the server

~~~
bvm
so, Meteor?

~~~
alexro
This front-end db should be separate of the UI/navigation. So, not Meteor

~~~
btown
To be very fair to Meteor, they're trying hard to separate their UI/rendering
layer from their front-end data layer [1]. There are prototypes where you can
build an entire frontend in React from the top down, taking Meteor collections
as stores and passing them down your hierarchy or just including them [2].
Still rough around the edges, but Meteor's going in the right direction here.

[1] [http://info.meteor.com/blog/meteor-the-missing-
infrastructur...](http://info.meteor.com/blog/meteor-the-missing-
infrastructure-for-building-great-react-apps)

[2] [https://github.com/jedwards1211/meteor-webpack-
react](https://github.com/jedwards1211/meteor-webpack-react)

~~~
jeswin
I wish Meteor nothing but the best, but React is no longer just a UI
framework. Relay encroaches significantly on Meteor turf; and its optimistic
update mechanism is arguably more flexible that Meteor's syncing protocol. In
addition, there's React native and deep integration with tools such as Flow
and Include.

There should be space for Meteor and I don't mean to be discouraging, but this
is generally a good time for framework authors to internally debate how the
competitive landscape has changed and the best path forward.

~~~
btown
Unfortunately, Relay is significantly further from "just working" with push
and write-once-run-everywhere-including-your-database query language, than
Meteor is from "just working" with React. If you want a realtime immediate-
mode-rendered web application without writing tons of boilerplate for data
handling, and duplicating business logic in your server (i.e. GraphQL
implementation) and client, Meteor+React has the edge today. You're right,
though, that frameworks built on Relay+React will eventually catch up. I'm
also looking forward to that day.

------
dominotw
I recently got rid of redux, react-router, immutablejs ect

from my reactjs app. I can't believe how much simpler my app got.

There is a lot of architecture astronautism going on in js world right now.
Just be skeptical of it.

~~~
tajano
I'm curious to know how complex your React app is.

I'm just starting to integrate Redux (and possibly Immutable) into my app, and
initially I'm a bit surprised by how Redux can make simple things much more
complex. I'm hoping it will pay off by end up simplifying complex things down
the road.

In any case, it feels like we're currently at the "peak of inflated
expectations" with respect to React and Flux/Redux.

------
jon-wood
This feels similar to NuclearJS[1], which I've yet to use in anger, but seems
like a pretty nice wrapper on top of using one big immutable data store.

[1] [http://optimizely.github.io/nuclear-
js/](http://optimizely.github.io/nuclear-js/)

~~~
woah
I found Nuclear to be pretty great. It's not as pure or functional as
something like Redux, but it has everything you need, and it is well tested
and mature.

------
marcofiset
If you're going to borrow every idea from ClojureScript and Om, why not simply
switch to these technologies instead of relying on so many libraries?

~~~
davedx
Many companies will simply not use ClojureScript, it's too niche and too hard
to find developers for at the moment.

It's much easier to find JavaScript developers.

~~~
collyw
Many developers are capable of learning a second language. If they are stupid
about hiring they will insist on experience with ClojusreScript. And lets face
it most companies will do that.

~~~
reustle
Really? Good luck convincing good JS developers that they should actually be
doing Clojurescript at work instead. Maybe you'll have better luck at a local
frequent clojurescript meetups (probably doesn't exist).

~~~
gknoy
I work near a team of people I'd consider "good JS developers". If I were to
just go over to their workspace and say, "We should totally use
Clojurescript", they'd look at me with a mixture of "LOL, Emacs" or "This
guy's a loon".

However, if I were to give a presentation talking about how I took X and
rewrote it as Y in Clojurescript, and the benefits of doing that -- time, ease
of debugging, code readability -- I'm pretty sure that they would not dismiss
it immediately. (Of course, this would require me to actually learn
Clojurescript well enough to rewrite my JS things in it. ;))

------
Cshelton
I've been using a flux architecture with Immutable Stores and cursor like
things that only give the state to the components that need it. I'm using
Facebook's dispatcher as well. Maybe I missed it or the author is just
describing an alternative, I don't see the advantage of using js-csp over FB's
dispatcher?

------
bpicolo
I feel like every new architecture for flux lately comes at the cost of a lot
of code complexity. The global state is becoming extremely common too, and it
feels like a big anti-pattern. Not really a fan. I do like the more pure-flux
Alt at the moment. I felt quickly put off from Redux after going through docs
for a while.

~~~
dustingetz
databases are global state

(The design pattern here is separation of code from state. OOP couples code
(methods) and state (members))

~~~
bpicolo
I realize that about databases, yes. I think the particular ways that
frameworks have been trying to handle state are bad patterns. Not sure what
would be better at the moment, but currently it's a mess.

------
Void_
It feels so complicated. Every one of these "React architectures" does. And it
doesn't even include any networking.

Compare all that to Meteor.

~~~
iLoch
Networking is a nearly trivial layer on top of the Flux pattern. I've found
this especially true with Redux with the ability to easily wait on promises to
mute state.

Meteor has its own problems too. The nice thing about Flux architecture is
that you're not married to the network. Take my comparison with a grain of
salt because I haven't given Meteor a try.

~~~
tajano
Slightly off topic, but what library do you use for networking with React?
Almost every code sample or tutorial uses jQuery's AJAX methods. Bundling
jQuery seems excessive when just using those methods, but is there not a
reliable alternative?

~~~
sotojuan
There's tons, but the common one is fetch: [https://github.com/matthew-
andrews/isomorphic-fetch](https://github.com/matthew-andrews/isomorphic-fetch)

~~~
iLoch
Yeah I use fetch and a Redux React promise middleware module.

------
elcct
Very interesting, thanks!

