Hacker News new | past | comments | ask | show | jobs | submit login
Why We Moved to React (instacart.com)
158 points by sorcercode on Feb 27, 2016 | hide | past | favorite | 141 comments



In this way, it seems that React makes a lot of sense as a migration path. Honestly, I find flux/redux and other unidirectional data flows are much easier to scale than most patterns for UI development, especially class/oo ones.

That said, React is just a part of it, and some flows are counter-intuitive in React. This must be said because it is true... that said, I find that React is far better, all around than most of the other options I've used, and I've been building web apps for two decades now.

I'm currently working on supporting an Angular 1.x app, have a proof of concept built in Redux+React, and another app I've been instructed to write in Angular 2. I've also built a couple of SPAs using Backbone. In the end the Redux flow has meant less code as features are added, and I'm working towards writing my Angular 2 app with that in mind. Modern React takes a lot of tooling setup to get started (or starting with someone's existing boilerplate), but the shear amount of boilerplate code that you have to write with Angular2 is just unnerving. The DI model is awkward, and I'm not enjoying it at all...

The Redux+React proof of concept is for half the functionality of the Angular 1.x app, I'm pushing for the change in the next version... with about 1/3 the functionality, the code is 1/10th the size, and there's a lot less complexity... A single state tree, in the end is easier to reason with, even if you're only looking at part of it. It's much easier to deal with, even with scale than trying to add more message channels in an application between components. Getting used to separating actions via a single dispatcher, and the resulting state changes takes getting used to... but so much easier in the end.


> with about 1/3 the functionality, the code is 1/10th the size

Yeah, that's the usual 80/20 rule at play.


Angular CLI helps much with the Angular 2 boilerplate code: https://github.com/angular/angular-cli


Have you checked Elm? I know there is a big difference between switching frameworks and entire language, but the benefits are really nice. Elm really enforces unidirectional data flows throughout entire application. For me it's like react on steroids.


I've been using Redux, and it is pretty much required if you have multiple components who need to update when a single state changes.... but pretty unhappy as the amount of scafolding required. It's not nearly as "isolated concerns" as it should be.


Take a look at MobX. It's a different paradigm that requires very little boilerplate and results in more isolated components that react independently upon changes to state. https://github.com/mobxjs/mobx


Right. I can give two alternatives.

1. Elm. I was just about to throw away the idea of Flux in a web app till I saw TodoMVC implemented in Elm. In Elm everything is immutable, and as a functional language, it has a lot of helpful syntax to help you deal with immutability. Shoehorning immutability into Javascript seems to require a lot of scaffolding by comparison.

2. MobX, it's been mentioned elsewhere but I can't help but sing its praises. Writing in MobX means that using controllers/dispatchers/actions/supervisors or another form of managing dataflow returns to being an architectural concern you can pattern to your application's needs, rather than being something that's required by default for anything more than a Todo app.


Do you know of a worthy Redux+React boilerplate project?



I've got a list of some particularly good ones at https://github.com/markerikson/react-redux-links/blob/master... . There's also a link to a little "starter kit search engine" someone built that lets you filter about 50-60 of them by various attributes.


http://teropa.info/blog/2015/09/10/full-stack-redux-tutorial... is good if actually want a hand-holding walkthrough rather than just a boilerplate.



https://github.com/GordyD/3ree is a good starting point for React + Redux (+ RethinkDB).


My anagram is r3k[1] (React, Redux, RethinkDB, Koa) ... Still a work in progress. Wanting to get to the point where I have an adaptive login (local account, google, facebook, twitter) and some public/private pages with universal rendering. Been working on it as time permits.

[1] https://github.com/tracker1/r3k-example


I like the idea of React. I like it even more when you take out all the frills and boilerplate. If you haven't already, I would encourage you to give Clojurescript and Reagent a try:

https://reagent-project.github.io

I decided to use it for a small client for a chat server my company runs. The initial environment setup on OS X wasn't the smoothest, but once I got that taken care of the actual development was very pleasing and quick. You need to know just a few core concepts and then you can more or less replicate the common patterns you use in React - application state, component properties, local component state, initial values for local state, etc.

Along with that, you get immutable data structures and the benefits of the Google Closure Compiler out of the box. Give it a shot!


If you're ready to check out Clojurescript, I strongly recommend trying out Hoplon:

https://github.com/hoplon/hoplon

It requires a certain shift in thinking when coming from pretty much any other framework. However, it avoids all of the unnecessary complexities of React by exposing the DOM elements directly as functions. The mindshare behind it might be low compared to Om or Reagent, but the people that are using it are pretty active at Clojurians slack channel #hoplon and on IRC (freenode, #hoplon). It's also FRP-based and pretty efficient. Highly recommend!


I must've done something wrong, but I haven't attained that "zen" part when I tried to use React. On the contrary, it felt like I'm writing a giant pile of boilerplate code "just to use React", where there shouldn't be any.

A simple, almost ToDo-like form quickly grew to 7 files, averaging 100 SLOC each, with a air-filled boilerplate-feeling classes (yet not lacking works-by-convention magic) that juggle data through those render -> onClick={e => this.onItemAdd(e)} -> onItemAdd -> addItem -> update -> UpdatePromise -> handleUpdateItems -> render loops.

Sure, everything's logical but that feels like I'm deeply stuck in the wheel of Samsara, writing code for its own sake and not attaining any Enlightenment. ;)


> render -> onClick={e => this.onItemAdd(e)} -> onItemAdd -> addItem -> update -> UpdatePromise -> handleUpdateItems -> render loops

you seem to have fallen prey to overengineered examples.

that example should be

>> render -> onClick={e => this.onItemAdd(e)}

thats it, data change should re render the tree.


Well, maybe. But I also wanted it to sync up with the server too (onItemAdd actually updated component's own state with extra "save in progress" flag, handleUpdateItems would clear it later).


well then you are doing much more than

  A simple, almost ToDo-like
You can do things like writing sever-syced component,mixin ect .


Me either. I understand the benefits but for side projects and stuff it's just not a very fun language to learn or use. Even Angular, with it's weird paradigms, seems more natural.


React has been quite nice, and very fast to work on. But there's one aspect that's concerning.

You have state and props, and the React tree diffing algorithm attempts to make some minimal set of changes that preserves state. However this algorithm is a heuristic, and so it's possible to hit a case where your component gets a different component's state.

For example, say there's a text field which has keyboard focus. Another text field is added above it: the keyboard focus should stay in the bottom text field. But React has no notion of identity and doesn't know whether the top or bottom text field is new. All it sees is a diff from one text field to two, and who knows which one will get focus!

React's answer to this is to introduce identity by assigning each component a key, and that works. But this is reactive: I notice a bug, and fix that case by assigning a key, but still most elements do not have a key and it is not reasonable to add one. I'm stuck hoping that the opaque tree-diffing heuristic is correct enough for my case.

How do other React users handle this? How do you go from "seems to work" to "I am certain React's tree diff will assign the right state to the right components in all cases?"


I'm seeing a lot of bad solutions to this problem written in response to you, so let me say "Do not ignore the the console warnings about array item keys" and list out some gotchas:

* Supply the key to the top level list item component. Do NOT have the list item component define its own key in its render method. That is not how it works

* Don't use the array index for the key. Use something that's unique to the VALUE.

* Don't use _.uniqueId() or similar in any render loop. It will trigger a re-render every time, even if your underlying data has not changed.

* If you use _.uniqueId() outside of a render loop, for example to set a temp ID on a brand new data model (what Backbone does by default), and you have an isomorphic setup, make sure that your client and server counters stay in sync. The server version of _.uniqueId() will just keep counting up forever unless you do something about it.

You really need to try to find something unique (or unique enough) about the data itself. In the case of strings, use the string as the key. If the case of objects, if you really HAVE to, if there is nothing else that could possibly work right, you might get desperate and JSON.stringify them to make the key. Hopefully it doesn't come to that but it's still often better than alternatives that force full DOM reconciliation on the whole list.


Shit. I've been using uniqueId from Lodash b/c I wasn't sure what was a better solution. What if it's a static, non-DB-fetched array? Would array indices still not suffice?


If the array does not change over time, using array indices is perfectly fine. You can use anything as a key as long as you guarantee that it stays the same for that specific element. If you don't change or reorder the array, the element's index does give such a guarantee.


This should really only be an issue when the children of an element are all the same type of element and are at the same depth level. For example, this is very common for li elements in a ul element.

We try to keep the structure of the html so that wrappers generally keep different UI components separate from each other. In other cases, like in the example in the blog post, we just use the index from the .map() loop to add a key to every element we know will need one. React should also warn you when this is an issue.


> we just use the index from the .map() loop to add a key to every element

Doing this could hide weird bugs. Let's say we render a list of posts with "remove" button for each one. The user clicks on "remove" button, we modify the underlying this.state.posts. And on next re-render removed post key would be assigned to the next post! The next post could inherit just-deleted post handlers, for example.

It's much better to use unique keys like database ids.


Great point. This has to be the funniest and most confusing bug when you first encounter it!

If your list is totally static, an index will do the job. However, we usually end up appending something like an id from the db since almost nothing on Instacart is static.


Wait, you're using the loop index as the key? This is React's default behaviour, and it's what it warns you about. Assuming you're looping over some kind of list of models, use the model's ID instead.

Basically, no matter where in the array a value is, it should always have the same key.


Moreover, you'll get a warning in the console if there are ambiguous children telling you to add keys.


What prevents state cross-talk from distinct components? Do we just hope that their structure is sufficiently different that React doesn't mistakenly infer identity?

Even the simplest elements like <p> have state and meaningful identity, like their text selection range.


NO! Don't use your collections indices as a key, that defeats the whole purpose. Your indices can change without content changing! You want to use item.id or something not as volatile as a collection index!


As a side note, I use uniqueId() from the venerable underscore.js utility lib (last version is 5,7kb only).


Won't that cause the element to get a different key every time render() is called, causing React to think each is always a new element thus throwing away the state every render?


You are correct. _.uniqueId() will absolutely wreck your list rendering performance if it is called on every render. 99% of the time, you can find a better unique identifier, but if you absolutely need something like _.uniqueId(), it should never be called in the render loop. It should be attached to the data being iterated over, in advance.

But... the other problem with _.uniqueId is that in an isomorphic setup your server will just keep counting up and up while your client will start from 0 on every page load. So the first time you reinflate React on the client side the checksums won't match and will cause a full-page re-render.


I only do that on the client, and yes, as a matter of facts, things are rerendered each time. But we are talking of a couple uls with <10 elements, frankly the eye doesn't catch anything at all... Honestly, the real damage of this bad habit of mine show off when I've to explain to my co-workers why it could be bad to do this for every situation.


I think the correct way to handle this is to always set a key. When I try to render some list items without a key I get this warning in the console:

Warning: Each child in an array or iterator should have a unique "key" prop. Check the render method of `YourComponent`. See https://fb.me/react-warning-keys for more information.


one of the biggest changes was accepting that React is different from old way of doing things like with jquery.

I used jQuery to build 4k loc applications. It's a fucking blast when you are just wiring up the template and watching the UI come alive...to me that was the power of jQuery. No need to think, just go and make everything stick like glue.

Angular.js was also right in that regard....add annotation to HTML. but this shit doesn't scale when application grows.

I'm still frustrated that I can't write shit in jQuery anymore because HN have collectively ruled against it and I guess at 4k loc it has become very hairy.

But I still argue if your needs are pretty small, like make a small widget app that has two buttons and makes ajax request to an endpoint, no other frontend framework can even touch jQuery in this territory....

In fact the overhead of having to think about states, structures, components organized in hierarchy...this shit adds to my stress and I can't experiment fast...but then also was the stress from not being able to add new features because the jQuery app grew in complexity....

difficult times gentlemen difficult times. I've been holding on to jQuery since 2009...maybe it's time to venture out entirely with React.js? Or should I crawl back to the comfortable cave that is jQuery where I can make anything very quickly.


I'm also still in the jQuery cave, for the same reasons you are. For most of what I do, it's enough, but on my current app, there are a couple of places (complex booking forms) where the code can get messy really fast. I might give React a try when the opportunity presents itself.


I'm pretty sure you can use both. I use jQuery more like an enhanced javascript. React I use for designing real interactive components.

If you have a small javascript feature to implement, just write in jQuery.


KISS. Keep it simple and straightforward. Once been extjs then come to weird mvc pragma come become line of code(LOC) become triple larger. Then i moved to jquery, it breeze to code.Have try learn new tech like angular,backbone but still fall back to normal javascript and jquery.Maybe i'm to old to learn new tech. :(


You're not too old. The new frameworks just don't make much sense. You don't need any of them to write applications. They just bloat everything, create additional dependencies and don't help you much. You spend all your time figuring out how to do things limited by frameworks's scope rather than getting things done. You can generally write 90% of what you'll need from any framework in 90 lines of code and create nice abstractions yourself. Don't use frameworks and don't let the peer pressure get you sucked into this nightmare what frameworks are.


Don't let the peer pressure get you down. Stick to jQuery. Like you said, you can get anything done with it very quickly. You don't need any of these massive frameworks to build web applications.


If you want to make components dynamic on top of regular HTML, like jQuery, but want to wrangle some decent architecture and scalability out of it, I can't recommend Vue.js[0] enough.

[0] http://vuejs.org/


There's still a lot of nice middle ground between jQuery and React.

When I started venturing beyond jQuery, things like Knockout were a god send for simplifying data-binding (and they are still around).

React is fine, but it's really no silver bullet


reminds me of this https://github.com/ermouth/jQuery.my

have yet to use it but seems like that handles data binding....


you may find https://github.com/leeoniya/domvm interesting.

Disclaimer: mine, and has about another month to 1.0 stability.


It's clear why using React in your Backbone views is beneficial, but I'd be genuinely interested to know what tangible benefit moving the models (and, thus, entirely from Backbone I guess) to flux/redux etc brings you, besides just keeping up with the latest conventions.


The backbone model api was made with totally mutable data in mind. React, on the other hand, only works well with immutable props and some mutable state in the top levels of components. That's our first issue, for sure.

Backbone also has a dependency on jQuery, which isn't very useful in React apps since mutatuing the DOM (one of jQuery's main purposes) is a no no. So most of the Backbone library isn't very useful to us anymore. I do still really enjoy the backbone way of fetching and saving models, especially in a Rails context. But I think we can get those features in other ways.


That's pretty much experience too: our apps that use React + Backbone, I find myself more and more using a fraction of the features (very basic API integration (fetching, saving) and the router), both of which could be easily replaced with something else. Not that it would be particularly hard to extensively use Backbone with React, it's just that there seems to be other (better) ways to do the same things too.


I use React and Backbone too. Here's the source code: https://github.com/pixyj/feel/tree/master/client/app

I use jQuery for animations and also for non-crud pixel-level DOM manipulations as in the graph shown in the home page: https://conceptcoaster.com/course/python-tutorial/ In the graph, I need to dynamically calculate height of certain elements based on the height of others. The height cannot be predicted in advance. Can React work for such cases too?


You definitely can achieve it with React sans-jQuery, though it is definitely more boilerplate/code than the equivalent jQuery call. This is an acceptable trade-off for us, but might not be for you, YMMV


Really like the app. I like the top progress bar loading animation. I'm assuming this is the relevant file? https://github.com/pixyj/feel/blob/master/client/app/base/js...

Trying to figure out a way to implement this with React + React Router...


Thank you! Yes, that's right! I'm not familiar with React Router yet though :(


Taking Redux, for example; doesn't a Redux store's getState, dispatch and subscribe methods roughly map to a Backbone model's get, set and on methods respectively? Isn't the immutabability of data in a redux store an implementation detail of the store? How does this impact the React views?


Unlike Backbone models, Redux state doesn’t have setters. Components can’t just go ahead and change it as they like.

This adds more ceremony around changing the state but in my experience (I’m biased: I wrote Redux) makes such changes easier to debug and test.

Every change comes as an action that the whole reducer tree can handle, so changes are predictable and reproducible if you record actions. You can change how actions are handled without changing the components dispatching them. A good example is how your components can emit SHOW_NOTIFICATION action but you can refactor your reducers from allowing only a single notification at the time to keeping a stack of notifications, without changing any of the components emitting them. This is what separating actions from state changes gives you.

You can log every action and see the entire state tree before and after the action. This, in my experience, makes it easier to fix incorrect mutations spanning across multiple entities. If the user clicks a button and the state is updated, and then a network response comes, and the state is updated again, you can log diffs between the state changes and have a clear picture of everything that’s happened. In fact Redux DevTools even provide a UI for that, e.g. https://github.com/alexkuz/redux-devtools-inspector.

One feedback I hear particularly often about Redux is that people who never wrote unit tests for front-end apps started writing them because it is just so easy to test reducers. You don’t need to mock any dependencies or simulate AJAX requests because any new data (whether local or remote) comes in the form of actions. So you can just call the reducer with a state and an action, and assert that its output matches what you expect.

With a single state tree I found it easier to ensure that all state is normalized and you don’t have duplicate data. In Backbone, it is encouraged that models are instantiated as you parse the request which makes it non-trivial to normalize them and merge the changes. In Redux, any merging is going to be explicit, and you can always inspect the single state tree to make sure the structure is normalized and matches what you expect it to be.

By contrast, in Backbone, models are active records so user.followUser(anotherUser) will set() a few flags on itself, fire off an async request, set() fields on another model, then possibly revert if the request failed. This is pretty hard to do consistently because there is no central point to mutations. You also have to build some sort of cache and entity resolve mechanism to make sure you don’t have duplicate out-of-sync models describing the same data.

Finally, in Redux mutations are forbidden so it is easy for the views to bail out of reconciliation if the corresponding state fields have not changed. In my experience, Backbone doesn’t make such optimizations easy because it was designed with completely mutability in mind.

So Redux, in a way, is similar to Backbone, but also is very different.


Personally, I'd say the biggest similarity between Redux and Backbone is that both are simple, minimal, "no-magic" implementations of a few specific concepts, and have communities that have built addons to fit additional use cases.

Backbone is really just an event bus, some smart wrapper logic around updating an object and an array, and a nicer setup syntax for jQuery event handlers for a particular element tree. People have then built addons that handle relational models, derived data, view lifecycles, and so on.

Redux is just putting all/most your data in a single "model", making sure all writes happen explicitly and immutably, and firing a single "change"-like event. From there people have built various ways of organizing side effects, listening for specific changes, and hooking into other libraries.

So, both simple libraries that form the basis for an ecosystem, and let you pick-and-choose the pieces that you specifically need.


Yes, exactly. I would argue that Redux has an even smaller scope than Backbone (e.g. it doesn’t handle views or AJAX) but the landscape has changed enough that this is not necessary for a state management library. But it definitely fills the same niche.


Thanks for the comprehensive reply. I think this answers my original question well. But in my follow up, I was basically asking if, from the perspective of the view, it makes much of a difference if it's communicating with a Backbone model or a Redux store.

P.S.I actually recently watched your Redux videos. Very nice!


>But in my follow up, I was basically asking if, from the perspective of the view, it makes much of a difference if it's communicating with a Backbone model or a Redux store.

I think it makes a difference. When you work with a Backbone model, you directly modify it:

    model.set('completed', true);
When the logic changes, you need to change the call sites to call a model method or several model methods.

On the other hand, with Redux the view specifies what it wants to happen and not how:

    dispatch({ type: 'TOGGLE_TODO', id })
When you need to change how the whole state tree responds to that change you don’t need to change the components. This is the difference.


Thanks for the insightful explanation. Adding https://github.com/atmin/freak to the comparison (disclaimer, I'm the author):

* it supports set operations, `model(‘fieldName’, newValue)`, like Backbone and unlike Redux, which trigger only the necessary update actions in the (implicitly built) dependency graph. set is idempotent, even if your computed properties have side effects

* it has .on() method

* "You can log every action and see the entire state tree before and after the action.”. In freak, too:

    const model = freak(statePOJO);
    const history = [];
    model.on(‘change’, prop => {
      // change is called exactly once per mutation
      history.push({...model.values});
    });
freak’s README is a literal test suite, consisting of state changes and assertions.

Probably it's a good idea to add 'beforeChange' event, to make it possible to cancel a mutation.

* it's currently implemented internally using mutable data structure, but this is implementation detail and can be changed to immutable data in the future, allowing simply `history.push(model.values)`


Since when does Backbone depend on jQuery?


> Backbone's only hard dependency is Underscore.js ( >= 1.7.0). For RESTful persistence and DOM manipulation with Backbone.View, include jQuery ( >= 1.11.0), and json2.js for older Internet Explorer support. (Mimics of the Underscore and jQuery APIs, such as Lo-Dash and Zepto, will also tend to work, with varying degrees of compatibility.)

It's not a true dependency but it's a default companion and optional dependency (see Backbone.$).

Source: http://backbonejs.org


Personally, I prefer more web-component like frameworks. Vue.js is more usable, and easier to understand than React, but stuff like React Native is why React.js is worth learning.

I strongly dislike the JSX syntax as well. Its messy, and difficult to read. I would like my to write my components as dom nodes, like with Vue.js, Riot. The way that react.js handles css, is also messy. I would rather just defined a <style> tag like in Vue.js.


> I strongly dislike the JSX syntax as well. Its messy, and difficult to read.

I've read quite a few criticism of JSX but "difficult to read" is a first. It's not significantly different than any templating system out there (eg, ERB). It's just XML with interpolated code, what's confusing about it?


Well, now.

Firstly: context switching is an inevitable inconvenience, but in JSX you're context-switching line by line between two radically different syntaxes.

Secondly: switching into what? It's not HTML (Angular templates, for instance, are not going to win any beauty contests, but they are technically valid HTML). XML? No, not that either. So ... something that looks kinda like HTML/XML, but which isn't really. It's perfectly legitimate to sacrifice aesthetic elegance for the sake of adhering to well-understood standards. But if you're not going to adhere to that, then why pick something that is merely similarly ugly? I don't get it.

Thirdly: templating/view layers always face a trade-off - either they are embedded within the host language, or they use an external DSL which is parsed/compiled by the host language. The trade-off is: better change of 'correctness' and cleaner interop with the rest of the language if it's an internal DSL; on the other hand, with eternal DSLs, at least the possibility that non-engineers will be able to work on things. With JSX, you end up grafting an 'internal' DSL simply by adding a whole pile of syntax to the core language. You don't have the advantages of the separate template language, and you lose some of the advantages of the other by requiring a whole pile of extra tools. JSX is an attempt not to choose, in a situation where compromise is basically impossible. Hence its extreme awkwardness - just like E4X before it.

React has done some good things: it's put performance on everyone's agenda in a big way (Hallelujah!), and it has acted as a testbed for interesting front-end architectures. JSX, however, I feel is a serious mistake. I actually enjoy writing React code through Reagent or similar, but in native JS and especially JSX, it just feels awful. I just don't want that in my editor window.


> It's perfectly legitimate to sacrifice aesthetic elegance for the sake of adhering to well-understood standards.

React goes out of its way to make it look like you're working with the real DOM, but in a different way. Take the event system for example: https://facebook.github.io/react/docs/events.html

In that sense its even closer to the standards than Angular is - it still uses events instead of databinding.

> the possibility that non-engineers will be able to work on things

Its highly suspicious that it was ever possible because of tight coupling between template and its data. Just look at an Angular controller and view. Tell me that two different people can work on that in parallel, one on the JS part, the other on the HTML part. Its impossible.

At best you can have a designer work on the HTML part first, then a programmer can import it (a fancy word for copy paste + add all the dynamic behaviour), then perhaps the designer can do incremental design-related fixes but might need to consult the programmer regarding the data. The programmer can also do HTML fixes but might need to consult the designer regarding how they would look.

Lets see if that workflow works with JSX:

  * copy-paste: check
  * add dynamic behaviour: check.
  * tweak and maintain the design: provisionary check:
If the designer really can't handle the surrounding JS, (although given what you are saying it sounds more like the programmer cannot handle the sprinkled HTML), you can move the render function in a separate file:

  module.exports = function() { return (
    // JSX goes here.
  ); };
Problem solved.

Anyways, this is just staying inside the box with old aesthetic sensibilities developed from a bygone dark ages era. React is a peek at what HTML and JS could be, if only they actually worked together. Its also a snide remark * implying: "Hey WWW, you're doing a crappy job at supporting web applications. Let me show you how its done"

* not saying its intentionally snide, just that it might come off that way


Watch out for space between words in your designer's copy disappearing though, because React chose to deviate from the HTML whitespace semantics.

    <p>
      Hello and welcome to our fancy site, where you
      can do all kinds of cool things.
    </p>
In JSX, that text will become "...where youcan do all..." and the recommended solution is to type

    {' '}
to insert a literal whitespace. [Edit: See spicyj's response; I was wrong about this, but the behavior is different from HTML in other cases.]

That, plus the way JSX confuses the hell out of language modes—Emacs, GitHub's rendering—makes me want to stop using JSX. I just don't enjoy using it, and I really do enjoy creating DOM elements with normal JavaScript syntax.

But like so many other things people argue about... it's just preference, and ultimately pretty insignificant.


This exists for a reason. If you do this in HTML:

    <li>Hello</li>
    <li>World</li>
    <li>!!!</li>
You now have text nodes containing a space in between the <li> elements. These will subtly affect how the elements are rendered. In HTML, if you want to get rid of those text nodes, you have to write the elements on one line:

    <li>Hello</li><li>World</li><li>!!!</li>
Or use float: left|right styles to push the text nodes out of the way. Both are ugly solutions. With JSX, I don't have to think about that.

I've never even ran into your issue because I use React for web app development and so use translation strings (i.e. function calls) for pretty much all user-visible text. If you ask me, the trade-off React chooses here is adequate.


Sure. I'm mostly just saying you can't take HTML and cut & paste it into your JavaScript file.


(This is actually not quite true -- you only lose whitespace when one side of the linebreak has an element, not when both are text.)


Oh, thanks for the clarification. I was misremembering; I think my actual case was something like:

    <p>
      Hello, etc etc, please
      <a href="#my-neat-anchor">click here</a>
      to continue.
    </p>


Ah yes, I forgot about that catch. Its not always just simple copy-paste.


In fact, with v0.14's stateless function components the "render" function alone can be used as a component (except props are passed as an argument rather than "this.props")


> in JSX you're context-switching line by line between two radically different syntaxes.

Every programming languages has multiple syntax's to learn. That's just like saying switching from array literals to hash literals is an inconvenient context switch, or from strings to comments.


> what's confusing about it?

In my opinion the confusing part is mostly the fact that taking a markup language and embedding it into a scripting language is really awkward. You have two completely different types of syntax not only existing together but working together.

Also I've worked on multiple teams where designers will re-style and even change the markup of pages but trying to get non-developers to do this with JSX is just painful.

I find HTML and the DOM API awkward at times but since that's the final state I just prefer to work with that.


React does not require you to use JSX. Writing views with React.DOM is actually a quite nice alternative. This article gives an explanation: https://www.packtpub.com/books/content/using-reactjs-without...

However, newer React and Babel versions no longer compile JSX to React.DOM methods as the article shows, but other methods. Example for Babel: https://babeljs.io/repl/#?experimental=false&evaluate=true&l...


What is it that you don't like about react and css? React actually has nothing to do with CSS - 'by default', you just include a stylesheet as normal. If you want to upgrade, you can just something like CSS Modules with webpack's css-loader to make per-component stylesheets a lot better.


I'm a massive fan of Vue, and have been using it since v0.10 (IIRC); one thing I find React does better than Vue however, is large applications. Vue maps brilliantly to dynamic components that are rendered in your page (no matter where said page comes from, be it Rails or PHP or nginx serving static HTML), and while Vue.extend() and the new props/component hierarchy that v1 gave us moves us a long way towards handling larger apps, I still find it somewhat lacking at times. That's likely just a function of the sheer traction and community support React has, mind you.


https://www.instacart.com/ -> among the JS loaded: static-react-base-{id}.js 273KB. It it just me thinking that ~300KB of code, about to be evaluated in the browser is a bad idea?


I feel the same, but people use it because they can deliver things faster (and get the money sooner). Sure, after that the client will maybe get complaints about website crashing user's mobile browser on cheap phones but those phones will get replaced soon (5 years?) so the problem will fix itself.

On a second thought, how do you access the Contact form on a website you can't even load? :)


I'm interested in learning more about reusability. One problem I have with React is that I've made this component called Product and then I need another Product component but in a different context, for example in a listing with a thumbnail. Much like the carrot example. How do you approach this exactly? Shouldn't it be based on the same component somehow?


I think reusability is something that comes with practice. And I'm starting to think that "write once, reuse forever (without modifications)" is just a pipe dream.

Lately I've been realizing how easy it is to fall into the "abstraction trap". It's exactly your situation: I have a Thing. I need a new Thing that's slightly different, but I don't want to copy all the code! That's not DRY! It's paralyzing.

So instead of duplicating code I spend time trying to tweak Thing, passing in parameters, adding special rendering cases, and finally it works as Thing and a smaller Thing2. But it's a mess, and it's not factored well, and it'll be a nightmare when Thing3 comes along.

Check out this article from the other day: http://programmingisterrible.com/post/139222674273/write-cod...

In line with his idea of copy-pasting code, I think that's the way to go: copy all the code from Product, paste it into ProductThumbnail, and make it work. THEN refactor it, and pull out reusable bits... or compose the two somehow... etc.


I think the flow you write should always be the way you work with code. First make sure it works, then look how to improve it, what parts are expressing similar behavior, what parts are different etc. If I remember correctly this is also what Robert Martin advises in Clean Code [1]. And it makes sense, worrying too much over what the abstractions are going to be is only going to slow you down.

I normally go even a bit further (certainly on the frontend) and leave duplication until I wrote something 3 or 4 times (or until it has stayed there for a little while). This ensures that when I do write my abstracted component I'm actually making sure it is something that can, at least within that app, be re-used.

I do re-use React components between different projects but am also using the same Bootstrap theme so this makes a lot of components really easy to re-use.

[1]: https://www.goodreads.com/book/show/3735293-clean-code


I think the vague answer is 'use mixins', but they are generally unsatisfying. One hopes that using ES6 classes to define react components this way would allow proper inheritance, but the whole ES6 thing is a mess that breaks a bunch of other things (notably autobinding this). Upshot is my code remains repetitive.

Where possible you can use composability, extracting common function into a subcomponent, but this doesn't always make for neater code.


Ugh no. Please don't use mixins or inheritance. Composition is the way to go.

https://en.wikipedia.org/wiki/Composition_over_inheritance


Do you have any example React code using composition?


Same way you compose functions or HTML elements.

Functions:

    add(1,multiply(2,3))
HTML:

    <div>foo <span>bar</span> </div>
React:

    <Container> <Header>foo</Header> <p>content</p> </Container>


To be pedantic, that is not quite composition - I've made this exact mistake before too. Composition is where you have a function f o g (o being the traditional mathematical notation for composition), where (f o g)(a) = b satisfies g(f(a)) = b.

Composition is a useful tool, and so is writing functions like this, but they are two different ideas.


>but the whole ES6 thing is a mess that breaks a bunch of other things (notably autobinding this).

That's trivial to fix...


How?


Use one of the community-built subclasses of React.Component that provide auto-binding, like https://github.com/philpl/react-compat-component, or a utility function that's a one-line call like https://github.com/cassiozen/React-autobind.


If it's a class based component (ES6), it could inherit from the other.

But you could also extract the code logic in a product module, and reuse it in both components, which can even be pure functions.


This is not limited to ES6+, class/inherits/super are syntactic sugar for existing prototypical OOP idioms.


It's not limited to ES6, but it's not needed with the ES5 way of declaring React components, as mixins are supported there.


Actually you don't need to use React.createClass to use mixins, there is https://www.npmjs.com/package/react-mixin which implements them via decorators. Either I wouldn't consider inheritance and mixins interchangeable.


As I go over the impressive list of big sites adopting React [1] I feel there must be something wrong with this current survey [2], which states a mere 67 of the top 10000 sites are using it. Any insight will be welcome.

[1] https://github.com/facebook/react/wiki/Sites-Using-React

[2] http://trends.builtwith.com/javascript/javascript-library


While easier than before to do server side rendering, it's still non trivial to do a react app that preserves SEO and renders on the server if your app isn't already a nodejs app.

It would require running either V8 to render on the server behind whatever language your backend is already written in, or calling node to serve your backend, relegating your existing backend to an API (and tying the backend rendering to your API along with the Frontend to use the same API isn't simple either).


That is definitely one limiting aspect for some places. We actually have a similar issue, since we're a Rails shop first and foremost. Luckily there are a few tools we can use to make it work well with Rails. Maybe a future post!

I also think jQuery and other libraries with large usage are kind of Swiss army knives, so more people have more use for them.

I do believe over time React will become as pervasive as jQuery. Or possibly even the DOM api will eventually allow a similar style of building things natively. This seems to be happening to jQuery now :)


Indeed. We had to tackle this for Expedia's Viewfinder[0] (which was done by utilising nodejs as the server), and we're tackling it again for another project that has it's server-side rendering done in PHP. Interestingly, we are leveraging the v8js PHP plugin to be able to execute JS from inside a PHP context, sharing variables between them as needed. Though I'm not convinced its the perfect way of tackling this problem, there's still a lot of quirks and bugs.

[0] https://www.expedia.com/pictures


I looked into another alternative: dnode, although I think I'll still stick with V8js for now. I don't think it's avoidable unless you want to switch to a Nodejs API server as well.


The forceUpdate API is murderous for performance, since it causes the entire tree to do a vdom rerender, bypassing shouldComponentUpdate() checks. Should really try and find another way to trigger a re-render.


I'm not exactly disagreeing with you, but forceUpdate only bypasses the component's own shouldComponentUpdate check. It doesn't necessarily do a "deep" re-render including all of the component's children. The children have their shouldComponentUpdate check run as normal.


Definitely agree. In our real code we're much more sensitive of performance. This was just a quick way to show a simple way Backbone can be used with React.

I think it'd be interesting for us to do another post in the future about how we measure and improve performance within our React apps. There aren't a ton of articles about this with relation to Bakcbone, it seems.

Thanks for giving it a read!


Would definitely like to read that one. We have a backbone/react app and generally use your example pattern, but I can see how it would take a toll on performance at some point. What's the general pattern you use if not forceUpdate? I suppose you could use something like @setState(model: model) but you still have mutable models to deal with in shouldComponentUpdate. Have you guys come up with a good way to reconcile backbone's tendency towards mutation and the performance benefits of immutable props?


Yes and no, really. We mostly keep our backbone models as props and keep them immutable by pure convention. You really could just call set() on one of them and cause some problems. This isn't great long term, of course. Code reviews and code style guides help here for now.

We've also at times converted backbone models to simple objects at the parent level and passed them down that way. Keeps things simpler, but we lose some of the niceties of the backbone model api. Once the models are objects, you can use componentShouldUpdate pretty defensively if you need.

We've also used throttled and debounced functions for anything which gets hit very heavily.


shouldComponentUpdate is also slow, since it still requires all children of a big component to be tested every time, even if only one child needs updating.


As a C++/XAML mobile app dev, I'm baffled by how a common UI like this (lots of lists?) requires such a deep dive.


Saw your comment in another post about how the Start Menu is really just an XAML app. I was wondering, how did you guys make it transparent and blur? I have been trying to figure that out for the past 2 days and have had no success yet.


To attract young, hip developers, or to justify incumbent hip developers.


Dominic, when did you start rolling out this change, and how long have significant parts of production been on it?

I'd be very interested in a follow-up in a year, once it's grown to the size of the backbone app it's replacing, and been battle-tested (in prod and in development)


We've slowly been growing our React presence on the site for almost a year now. At this point, we're fairly close to the size of the original Backbone app as far as views are concerned.

We're still somewhat tangled in with Backbone, but it's been a great success internally. Performance-wise, development speed-wise and also developer happiness-wise we haven't hit too many snags.


I was checking out their careers page and they're looking for a senior engineer to lead 5 engineers, but they require masters degrees? Really? Newsflash: a one year degree isn't what's needed to be a successful team lead.


The next bullet point:

"Employer will also accept a Bachelor’s degree or foreign equivalent in Computer Science, Computer Engineering, Information Technology, or related technical field and 5 years of progressive, post-baccalaureate experience in a related field."

We don't require a Masters. Some engineers have one (or PhD even) but that's much less important than being a great engineer.


You missed my point entirely. A one year degree isn't the equivalent of 5 years of post-bac experience in the field, and that is your first bullet point, the "expected" and most discouraging one - folks stop reading after that. That some folks have masters or PhD degrees is great, but shouldn't be an expectation for a team lead role. I'm sure you'll have issues trying to attract talent with that kind of messaging and expectations.


> As an experiment, we tried writing a separate app to try out the popular Flux library.

Is there one 'popular Flux library'? Perhaps they meant redux? No other mention of it in the article.


There are lots of popular Flux libraries.

https://github.com/acdlite/flummox

https://facebook.github.io/flux/

https://github.com/reflux/refluxjs

http://fluxxor.com/

https://github.com/reactjs/redux

Each of these appear popular in their own right. Given they mentioned Flux, it probably is the actual Flux library.


Flummox, while amazing (and my favourite) has been deprecated in favour of Redux. That said, my personal replacement is Alt.js[0], which has the same style of architecture and API that Flummox had

[0] http://alt.js.org


Yep, it was the actual Flux library. However, we're not totally settled on that choice just yet.


Awesome! I had chosen flux for one project I was on and really enjoyed it!

Thanks for the post!



Saying CoffeeScript is simpler than JavaScript is the same as saying: I am going to make traffic simpler by removing lane delimiters, traffic signaling, lights, street names. You end up with a "simpler" language, but it is also less safe to use. Python will throw you an error with inconsistent indentation, but that's not the case in CoffeeScript. So any little messing with the whitespace, which is impossible to infer automatically, and you have a bug.

Then, you can massively auto-format JavaScript, use great tools that inference type information from documentation, etc... but with VomitScript, you are pretty much on your own. In fact using an advanced editor and nano will probably make no difference.

"Duh but I want to type less"... NOBODOY CARES about you typing less. If you care about typing less use templates in your editor and autocomplete.


Peguy's quote:

"And it will never be known what acts of cowardice have been motivated by the fear of looking insufficiently progressive."

becomes more and more relevant to the tech world.

We are managing a few lists. How is this so complicated?


If you have a less complicated way to build a big beautiful app like instacart, I'm all ears (that's why I'm reading this). Or are you just saying we should give users a CLI and be done with it?



Nice, looks very simple. But I don't see how it would make it simpler to build an app like instacart. Try instacart, the app is borderline magical. I've never seen a bug with their cart or the awesome realtime-multiplayer shopping. I'm guessing if you tried to build an experience like that with just intercooler, your codebase would end up being significantly more complex.


for newcomers is it too hard to find all the pieces that need to work with React to make a final product? I just started with Angularjs 1.x, while it has its faults I found it's easier to get started.

maybe React is better suited for the experienced who knows how to bootstrap all the components? I'm interested in learning React _after_ I get more familiar with the javascript-ecosystem, and it seems to start with angularjs will be a good approach?


What is Instacart using for its routing logic?


For now we use Rails on the server and a single backbone router for the the client side. This isn't how we want it stay. :)

We do have a couple side apps internally using React Router. We've liked it so far, but it's a pretty basic implementation.


No matter how I try to accept it, it is a really bad idea to embed views into business logic. You have no clear separation of concerns and this can create a lot of headaches as the sophistication of the application grows. Instacart is a great product, but it has a lot of room to grow still. What happens when you get into some deeper aspects of UX? I presume you do your own UX research and these highly segmented views are going to be a pain to manage.

You'll also need to worry about how you run BDD tests for specifications and scenarios. How can this be achieved in React as you write test suites for user stories and non-UI acceptance tests? How will this impact your continuous delivery/integration systems as well? You'll have to rewrite all your test suites into Jest, right?

There are architectural trade-offs for sure. Can you definitely say you've performed a thorough analysis before making this decision? There's a difference between having a clear strategy to move from one tech to another and knowing that the migration will not just bury you into a deeper whole than the one you think you're escaping.

http://aurelia.io/ is based on webcomponents (MVVM), ES6, and current web standards. It's amazingly simple and good architects can use their own structural patterns to create code that can actually scale with the product. DDD and BDD methodologies mesh perfectly into the development workflow, especially with Agile product development.

I wish you well, but I really think React is a short sell with dire consequences.


There's nothing in React which forces you to embed the views into business logic. React is just a view framework. How you structure your code is entirely up to you.


What you see mixed in with JSX is view logic, not business logic. I see the same thing in the Aurelia examples

    <h1>${router.title}</h1>
    <ul class="nav navbar-nav">
      <li repeat.for="row of router.navigation" class="${row.isActive ? 'active' : ''}">
        <a href.bind="row.href">${row.title}</a>
      </li>
    </ul>
Which is almost identical in JSX:

    <h1>{router.title}</h1>
    <ul className="nav navbar-nav">
      {router.navigation.map(row => (
        <li className={row.isActive ? 'active' : ''}>
          <a href={row.href}>{row.title}</a>
        </li>
      ))}
    </ul>
For loops and map functions aren't necessarily business logic, but they are view logic (and you'll see them in any sort of tempting or view system). React actually makes it very bad to include any substantial business logic into your templates as the render function is called many many times potentially whenever your data changes, so you want to include very minimal stuff in there.

> You'll also need to worry about how you run BDD tests for specifications and scenarios. How can this be achieved in React as you write test suites for user stories and non-UI acceptance tests? How will this impact your continuous delivery/integration systems as well? You'll have to rewrite all your test suites into Jest, right?

Exactly the same! At the end of the day, React is just Javascript. You still have your models in their own classes or functions, with your own API helper methods. How you write that doesn't change - no need for Jest. We're testing our entire app - including templates/views - using Mocha (and we're about to run tests in Karma in real browsers pretty soon).


The JSX is not the same as it is encapsulated in the render() method withing the JS file. This is the whole point of why this implementation is not a separation of concerns. The view is essentially embedded in the controller in order to simplify how a controller passes scope to the view.

This isn't the first time people have fallen prey to embedding HTML as a string into JS to write the DOM. 5/10/15 years ago, if we saw this, devs would just shake our heads. If anything React is an old hack, an anti-pattern brought forward again.

I misspoke about views in business logic, as you said, it is the controller logic, which should be decoupled from the view itself as well. The naive example of converting a webcomponent to a JSX component may look similar, but more complex components will only require greater complexity for the render() method to handle.

I understand your rationalization, but the crux of the arguments here are concerned with the anti-pattern React introduces and why developers who've come across this before have seen this as technical debt. The arguments for React are a matter of opinion, wherein the arguments against it are based on the practical principles for programming UIs, principles have been forged to be tried and true since the 70's.

I personally favor standards, such as webcomponents and OO programming for modules. I understand that this may not seem popular at this point and time, but 20 years of dev experience has taught me otherwise.


> The JSX is not the same as it is encapsulated in the render() method withing the JS file.

I'm not quite sure what you mean by this.

Anyway, I can't help but think that the distaste of the way React does stuff is due to first impressions and not actually using it in a meaningful way. I get where you're coming from - when I first saw React I thought the JSX was a terrible idea, raising many of the same concerns you have. I'm not sure what your experience is with it, but I definitely didn't like the syntax at first. Also, although we are talking about react specifically, usually you'll be using other libraries along side to it handle the other non-viewy type stuff.

But then I actually used it, and lead a reasonably sized team to create a non-trivial web app with it. People who have been programming since before I was born, and people who learnt React for this project. Not all of them love it, but everyone is very productive with it and we all see the benefits it brings and we haven't been burned by some 'anti pattern'.

Traditional programming common sense still applies here: bad developers are going to write bad code. When something gets too large, take another look at the problem and perhaps break it down into sub functions. If you're repeating thinks, create a common module for it. Nothing really revolutionary about that.

I'm not convinced there's no one working on or with React who's seen the pain of poor separation of concerns. There are lots of smart people working on React, both at Facebook and in the community, who are just as aware of the programming. "principles [that] have been forged to be tried and true since the 70's"

Additionally, the Aurelis example we both mentioned isn't a webcompoent. It's as much of a web standard as React is.


What I meant by the difference between the HTML in an Aurelia template and JSX is that the React component's markup has to be inside the its respective controller's render() method. That's the main issue.

I am not arguing about JSX syntax, but rather the principle behind it. How would I safely refactor a css class across hundreds of components in a safe way and not by find/replace? An IDE such as WebStorm actually tracks CSS classes by their reference in other HTML/CSS files and this includes CSS preprocessors. I know it's a safe bet to run the renaming, although I always preview the changes beforehand.

I'm a reasonable developer, but this is an anti-pattern that has been eschewed voraciously over the years. Your appeal to the intelligence of React's devs is an informal fallacy and doesn't change this fact.

I am not trying to be dogmatic here. Yes, breaking the 'rules' when it is warranted is perfectly fine. My argument here is that in this case, this anti-pattern isn't warranted and will be very expensive work with as the product grows. I am advocating standards and best practices. React sidesteps both for an unnecessary reason. It works, it's pretty awesome how fast it is, but it cannot scale with a product's lifecycle.

Web components keep the HTML in the DOM and are being officially adopted as a standard. They can be polyfilled with a lib from http://webcomponents.org/. Aurelia, although it is a framework, is extremely lightweight and greatly simplifies the use of web components. Polymer isn't as elegant, but it clearly demonstrates the idea of dynamic reuse. There are other alternative libs as well.

As an aside, ES6 is now standard and with Babel. Javascript is now closer to ECMA, as it was intended to be.

I think I've made my argument as clear as I can, thank you for a great (and polite) discussion. It has actually been helpful for me to voice my opinion and get a better understanding of the support behind React. Again, it's impressive how fast it is over other libs such as jQuery, but jQuery's always been bloated and is near the end of its usefulness. However that point doesn't detract from the very cool things that React can do in the right hands. I wish I could bet on it, but to me it's the wrong horse in the race.


I totaly agree with you. We need full decoupling between components. They have to be seen as pure functions, taking parameters and returning view modifications (and new values)


Stateless Functional Components in React!

    const ProgressMeter = ({ className, percentage }) => {
      const meterStyle = {
        width: `${Math.round(Math.min(Math.max(percentage, 0), 1) * 100)}%`,
      };

      return (
        <div className={cx('root', className)}>
          <div className={cx('meter')} style={meterStyle}/>
        </div>
      );
    };


Idiomatic React code would not mix views and business logic. (You shouldn't have business logic on your React component's; that belongs in a completely different part of that app.)

As for testing, you can do testing a lot of different ways, including BDD or DDD (I'm using a fair amount of DDD in the project I'm working on). But other than being a bit easier to test than many competing techs, there's nothing special about testing React code. And no, basically no one outside of Facebook is using Jest; it's a terrible testing tool. (I don't get the feeling you've spent much time writing or learning React? At any rate you seem to have some odd ideas about testing and React.)

Aurelia is great, but I think you're vastly overestimating the differences between an idiomatic Aurelia-based project and an idiomatic React-based project, and underestimating the flexibility which React enables.


There is a clear separation of concerns. The React component is the view. React doesn't tell you what to do with the other bits (although people seem to have plenty of different ideas). There's generally less lock-in to a particular way of doing things with a view library like React than with a whole framework like the one you're promoting.


There's nothing in React that makes you "embed views into business logic".

It sounds like your experience with React has been limited and based on just looking at things.

As with anything else you will have some "view logic" (example: to render "1 item", "2 items") but not necessarily any "business logic".

I'm not going to convince you in a comment reply but if you spend a significant amount of time with React you'll see.


There's nothing in React that forces you to use Jest or rethink your testing process.




Guidelines | FAQ | Lists | API | Security | Legal | Apply to YC | Contact

Search: