52 comments

[ 2.3 ms ] story [ 104 ms ] thread
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
so, Meteor?
This front-end db should be separate of the UI/navigation. So, not Meteor
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...

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

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.

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.
Maybe something like PouchDB, lazily synced with a CouchDB instance on the server ? I'd love to see a better integration, where for example global state would be automatically saved in PouchDB. You'd get pub/sub, history and synchronization for free, at the cost of PouchDB's performance (last I tried, it wasn't transparent enough)
Very interesting, thanks!
> 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.

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

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.

> 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."

GraphQL/Relay are not fundamentally bound to server state, they can be used to map client application state (from the "big atom") to components as well.
> 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.

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

Compare all that to Meteor.

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.

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?
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

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

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.
As I understand it, immutability makes management of state on complex objects easier to deal with. Whereas ImmutableJS the library makes immutability performant in JS. Someone please correct me if I'm wrong because I cannot seem to locate my source anymore, but I believe what ImmutabilityJS does is not actually deep-copy complex objects, but reuse references to nested objects that have not changed. Such that you get a new object, but not everything in the object is new, which is what keeps things fast.
When you use Immutable JS, you are taking a slight performance hit. You are creating a new object every time you change anything and returning it. But the benefit of not having to worry about unexpected changed or sometimes referencing something you didn't mean too is great.

The added performance can come from the equality checks. Like, do not do anything if newState === oldState. This has added benefit with something like React where you can use shouldCOmponentUpdate, which we returned false, will not call the render function. It can increase performance drastically on complicated things.

I think you know this, but just so that nobody gets the wrong idea- the new object created only uses as much memory as the difference between the new object and the old one. Immutablejs keeps track of the diffs and presents an interface to something that acts like a whole new object but consists of the old object + diffs.

So if you are replacing some in-place array mutation with Immutablejs code, this will use slightly more memory. However, if you are replacing native .map, .reduce, or .filter code with the equivalent Immutablejs, you will actually use less memory, because the built in methods clone the entire object.

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.

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.

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.

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

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.

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/

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.
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?
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.

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.
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).
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. ;))

Because parenthesis.
That's the most common objection, and it's the one that makes the least sense. If we were to count the number of parenthesis + square brackets + curly braces, we would fine that there is not more symbols in a LISP, just that they are arranged differently.
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?
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.
databases are global state

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

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.
Only the states that can be global need to be global. It's not an anti pattern to manage state inside the component.
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.

After getting rid of redux, what did you end up using for your data-model needs?
That sounds like a ton of work for any moderately sized application. It also seems like it would have diminishing returns as your app gets bigger, as that's when these architectures start to get useful. I have to be skeptical that your app has gotten simpler. If you've decided to drop the Flux pattern entirely then I can see your argument, because if you can do that then you probably didn't need to be using it in the first place. However I don't see this as a shortcoming of Redux or Flux. It just means they don't need to be used in every scenario, which should be implied.
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.

I agree about react-router and Immutable.js, but redux is tiny and the cognitive load is minimal.
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.
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.

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.

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