Hacker News new | comments | show | ask | jobs | submit login
React Fiber Architecture (github.com)
162 points by wanda 497 days ago | hide | past | web | favorite | 97 comments



This looks quite interesting - I got the impression that React would need quite a rewrite internally to accomplish incremental rendering.

One thing I noticed with the priority mechanism proposed - Angular 1 has something like this, but it turns out to be a complex api to understand and use. In fact, just about everyone stays away from mucking around there, and all usages of it I have seen in the wild is a straight up hack/misusage. I suspect that something like this would increase complexity dramatically.

Animation is a problem I feel might be worth studying different systems on, maybe not even just the browser. For example, Angular's implementations have ended up mirroring how Chrome handles animations after collaboration with the Chrome team. It probably shouldn't be singularly focused on how one browser has implemented it, but studying these systems is probably best for maximizing extensibility and performance.


Wow I'm at the bottom of the page and this is the first post about the actual article. One thing I was wondering was whether the approach they are taking might actually increase the complexity rather than decrease it. For example, when writing games, it's pretty common to have your physics engine and your rendering engine run at different frame rates. You get the incremental rendering by separating the two. This approach seems to tie the rendering of the internal model to the final rendering.

To be fair, I haven't really spend much time considering the JS animation API. I suspect this is really what's at fault here -- there may be no easy way to update the animation after the fact. Still, I can't help thinking that it would be better to try to separate the screen rendering from the internal model rendering...


Yes, this was my thoughts also. I've got a hunch that concerns have been incorrectly mixed here, leading to unnecessary complexity. But it's too soon to tell for sure


I believe the idea is to expose as little of the prioritization details as possible. E.g. updates triggered by a text input's change event will automatically receive higher priority. Or a DOM element with display: none will automatically receive lower priority. Etc.


The proposal doesn't sound like that was what was intended - it seems like it is left to the user to implement the fibers, with the work priority to be set by the user somehow. Indeed, a quick glimpse of the commits of the implementation reveals a priority system of values exposed directly to the user when creating components (see unit tests).


acdlite is correct here -- most users won't need to worry about priorities and it's unclear to what extent we'll even expose them. The unit tests do not describe a public API (and we're not close to settling on one).


Thanks for the clarification! I've been flying 16 hours today (Milan to SF), so I'm sure I didn't grasp the full significance of the concepts in the doc.


Can someone explain the benefits of React's DOM diffing model?

Rather than try to diff two DOM trees and optimize reconciliation, why not use one-way data binding and update exactly what has changed, with 0 reconciliation cost? Either way, the upfront work - linking DOM elements with model attributes - is the same. In JSX this is done by interpolating variables into the template, and in one-way data binding this is done via data attributes.

Anecdotally, I've found one-way data binding (using Rivets[1]) to be very fast in practice for a view hierarchy ~10 layers deep.

[1] http://rivetsjs.com/


Rather than try to diff two DOM trees and optimize reconciliation, why not use one-way data binding and update exactly what has changed, with 0 reconciliation cost?

If all of your rendered HTML corresponds 1:1 with the underlying data model, there's no particular advantage to the declarative approach used by React.

However, once you start to have relationships in the underlying data, so DOM events in one place can affect the desired DOM content somewhere else, simple one-way data binding is not sufficient.

For example, suppose we have an HTML table that needs to be rendered from some underlying data structure in our JS. How do you do that with simple one-way data binding -- what are you binding to what, exactly? If you're managing the HTML directly, you need to allow for things like rows being added or removed, not just updating the content of an individual cell.

Now suppose that table also allows you to sort by different columns and filter so only certain rows are shown. Rendering the correct HTML now requires keeping track of the underlying data model and all of the UI-related state, with the actual rows to be shown affected by several different factors.

Now suppose the table is going to have many rows, and pagination is required in the markup and controls.

You certainly can handle all of the related events manually, but in order to keep the rendered HTML correct you now need to write code that understands each possible change in the underlying data and UI in every possible context, and the combinatorics can get quite unpleasant here.

The alternative that declarative rendering tools like React offer is that you can specify what your rendered table should look like in absolute terms, using whatever inputs need to be considered but ignoring the existing state of the DOM. You still need to consider however many factors you have that affect the rendering, which might still be somewhat complicated in a case like this, but at least you only need to consider them from a single, neutral starting point, not relative to every possible starting point.


I don't get how your table example justifies the need for such a complex rendering pipeline.

There are plenty of template libraries that can optimally re-render a list/table after row insert/remove/move operations. Events generated by elements in rows can easily be associated with the proper data item.

React doesn't own declarative templating, and if you only use one-way databinding, and re-render only what changes (again, plenty of template libraries do this), you get `v=f(d)` and efficient updates. Why the extra complexity?


The table was just an example. The point is that if you use a declarative rendering approach, any non-trivial rendered output you want to generate only needs to be specified once, relative to a neutral starting point.

React certainly doesn't own the idea of declarative rendering, I agree, but what template libraries do you have in mind that offer that sort of functionality without either being limited to some specific case (tables, say), having questionable performance properties, or implementing the same sorts of techniques that virtual DOM-based libraries like React are using?

Perhaps it would help if you could give some concrete examples of the libraries you are thinking of, and point at some documentation (or give your own example code) to show how they would handle the kinds of events I described in my post above more efficiently and/or with cleaner code than a library using declarative rendering and a virtual DOM such as React.


Are you thinking of computed properties? If so, there are many libraries that have solved this, e.g.:

https://vuejs.org/guide/computed.html

https://guides.emberjs.com/v2.3.0/object-model/computed-prop...

When implemented using one-way data binding (as both of the examples do), this is more performant than DOM diffing.


No, I'm talking about arbitrary relationships in the underlying data model, such that arbitrary events from anywhere in the DOM can lead to arbitrary changes in rendering anywhere in the DOM.

Computed properties of the kind you linked to, when then used to drive rendering via one-way data binding, are a common but relatively simple example.

And yes, that sort of direct DOM manipulation is likely to be faster, often much faster, than DOM diffing in the cases it covers. The advantage of the more general diff-based libraries is their generality, not their rendering speed.


Can you give an example of a more general problem that you see React solving better? The example you gave earlier doesn't fully answer this.


Just imagine any non-trivial set of relationships in the underlying data, and then some rendered content that doesn't just depend on individual data points.

For the record, I haven't actually seen anyone address my earlier example with the sorted/filtered/paginated table yet.

Another typical example might be a complicated form where some fields are shown or hidden or have different options available depending on the values of other fields, perhaps including circular dependencies.

Another might be some sort of dashboard that adds a tab/tile/panel for each of some varying set of data sources and adjusts the layout or level of detail depending on how many sources need to be included.

Another might be rendering a chart showing several different data series over time, where the scales and positions of the axes are adapted to span the entire data set.

Of course you could manually update the DOM in response to relevant changes in the data in all of these cases, but keeping track of all the different variations and transitions gets old very quickly once your UI has a few different cases like this.


I think I understand what you're getting at - correct me if I'm wrong.

React's templating allows you to execute arbitrary JS logic when rendering, which is more versatile than simple one-way data binding.

My thoughts there are that I'd probably extract the logic first into the view model before passing the buck to the templater. For example, instead of filtering/sorting a collection in the template, I'd create a `normalizedCollection` computed property in the view model first (which helps with testing as well). In practice I've found that Rivets' binders are enough - showing/hiding/looping over data covers nearly every UI.

In the case of bigger chunks getting un/re-rendered (such as adding tabs/tiles/panels), you can take advantage of a framework that does sub-view management (such as Marionette[1]).

Computed properties can solve the hidden fields and multi-data series chart problem you mentioned.

[1] http://marionettejs.com/docs/v2.4.7/marionette.layoutview.ht...


React's templating allows you to execute arbitrary JS logic when rendering, which is more versatile than simple one-way data binding.

Yes, that's what I'm getting at here. In particular, you only have to write that arbitrary JS logic once to cover both the rendering and all the updating cases, so you get the same kind of automagic monitoring in your view that data binding gives but in the general case.

As an aside, nothing about React precludes using a separate view-model style layer between your base data model and the rendering logic to deal with computing derived information. Indeed, this is often useful as a form of cache if you have computationally expensive work to do when certain source data changes, for example to summarise a large data set or compute the layout for some complex visualisation. Again, computed properties seem to be a variation on this theme.

No doubt there are other ways to achieve the desired results, though inevitably they need their own version of plumbing to connect everything up, and in quite a few that I've seen over the years it's still difficult to co-ordinate updates and maintain good performance as systems scale up.

The main advantages of a library like React, in my experience at least, are that it is simple and universal in its design and interface, but also reasonably transparent about both behaviour and performance characteristics, with enough hooks that you can help it out in cases where the basic usage is inadequate.


I'm with you. All this complexity is baffling, when there's a very optimized rendering engine sitting there in the form of the browser, and soon a suitable component model.

If you wire up your components so that you just re-render the components that have data changes, you get the benefits of dom diffing, without having to diff.

You can skip all this framework JS, and just directly write an async-rendering Web Component. It's pretty compact and easy to understand. I just wrote up a sketch that would work with one of the incremental-dom-based template libraries:

    class AsyncWebComponent extends HTMLElement {
      constructor() {
        super();
        this.isLayoutValid = true;
        this.attachShadow({mode: 'open'});
        this._foo = 'bar';
      }
      
      // Accessors could be generated with decorators or a helper library
      set foo(value) {
        this._foo = value;
        // You could check for deep equality before invalidating...
        this.invalidate();
      }
      
      get foo() {
        return this._foo;
      }
    
      connectedCallback() {
        this.invalidate(); // trigger the initial render
      }
    
      render() {
        // Call into template library to re-render component.
        // If the template is incrementally updated (say with incremental-dom),
        // then only child components with data that changes will be updated.
        templateLib.render(this.template, this.shadowRoot);
      }
    
      invalidate() {
        if (this.isLayoutValid) {
          this.isLayoutValid = false;
          // scheduleRenderTask enqueues tasks, so they'll be run in order down the component tree
          // A simple and correct scheduler is to just enqueue a microtask with Promise.resolve().then(task)
          scheduleRenderTask(() => {
            this.render();
            this.isLayoutValid = true;
          });
        }
      }
    }
edit: example uses. In a template:

    <async-web-component foo="[[foo]]"></async-web-component>
When the parent component renders and sets `foo`, the child will schedule a task to re-render.

In JS:

    let e = document.querySelector('async-web-component');
    e.foo = 'baz'; // e schedules a task to re-render
    e.foo = 'qux'; // e doesn't schedule a task, because one is pending


Of course you can do manual dirty tracking. But why would you ever want to do that on every single component when you could get it for free?

React's DOM digging has zero cognitive overhead so the benefits are essentially free to me as a developer.


This is a sketch of a raw custom element with no library for sugar. A library that assisted in the pattern would presumably implement the accessors for you.

ES/TypeScript decorators would be an easy way to do this, or just a function that fixes up the class after declaration.


So implement the accessors logic and invalidation logic, centralize the rerender scheduling and you've rebuilt React.


What if your component has a lot of nodes? Do you re-render them all? I guess that's the reason they made react. Even if the state of component changes most of the DOM nodes of render component stays the same and re-rendering them would take too long.


thank you, thank you, thank you. Aurelia is an excellent system for this exact use of a web component.


My example was "plain" custom elements, nothing to do with Aurelia.

Last I checked Aurelia used a lot of the Web Components terminology, but didn't actually create or use custom elements. Did that change?


yes


So Aurelia components are web components? I can create one with document.createElement('my-aurelia-component'), and container.appendChild(), and the element will fully work and have it's lifecycle callbacks called?

I tried to look in the documentation, but couldn't see this clearly stated. It looked like Aurelia would have to be in charge of lifecycle to get dependency injection to work. Specifically, custom element constructors are called by the browser with no arguments: how does this work with Aurelia components that expect to receive constructor arguments via dependency injection?


that work is handled by Aurelia itself. You don't explicitly need to define the element.

http://aurelia.io/hub.html#/doc/article/aurelia/framework/la...


Sorry, I still don't get it. Take the CustomerDetail example in the "Component Instantiation Through Dependency Injection" section:

    @inject(HttpClient)
    export class CustomerDetail {
      constructor(http) {
        this.http = http;
      }
    }
If this really creates a Web Component, how does `this.http` ever get set? The browser will call the constructor with no arguments.

What exactly gets passed to `document.registerElement()` (for the v0 Custom Elements API) or `customElements.define()` (for the v1 Custom Elements API)? Are you saying that Aurelia generates and registers a separate custom element class? That's not in the docs. If so, how does that element find the instances to inject into the user-defined constructors?

The main issue that talks about custom element support is still open, and the answer really does seem to be that Aurelia can't create custom elements: https://github.com/aurelia/framework/issues/7

This unfortunately seems to confirm that Aurelia uses the terminology of Web Components, but doesn't actually use or create real Web Components.


yeah... You might want to try it out and read the docs before you make such claims

https://github.com/aurelia/web-components

remember too, the ES6 is transpiled. Also, I am done with the nerd war. If you have questions, use the gitter channel.


"nerd war"? Wow, good to see you go then.

That link you just posted is not contained in any of the docs or links that either you or I posted above. I can't actually find it in the entire documentation hub, so even if I did "read the docs", how was I supposed to find it?

Bye.


It's component diffing, not DOM diffing. I agree that the later is unnecessary. omponent diffing is an implementation detail that enables the declarations that makes React worth using.

Imagine a parent component that conditionally composes a Button that is either red or blue. You could track that button instance and flip the property if necessary. But that requires a lot of error prone boilerplate, as most real applications might have many states depending on many inputs.

With React you just define which variant you want in the render function of the parent. No state transitions necessary. React then does the hard work of understanding that you rendered a red button then rendered a blue button, so it should reconcile the two.


Data-binding is crap for many reasons. Here's a big one: inability to use immutable data types, except for the trivial case of a static component.

When you're diffing the vdom, the system doesn't care where the data comes from, i.e. the data can come from a plain js array or an Immutable.js list.

Second reason: When you have to worry about how to get your model to play nice with the view, that's a leak in the abstraction. This applies to ALL data-binding systems.


This is very cool, but the nagging issue I have with React is this desire to reimplement everything in JavaScript and bypass the Browser, DOM, CSS, etc. I've lost track of what benefits this really offers?


Could you elaborate? All React.js "reimplements" are components for DOM elements and custom event dispatcher that allows you to don't worry about browser quirks and differences in handling events.

There's also large difference between what DOM and VDOM mean and VDOM's not DOM reimplementation.


Why write every component in 3 different languages artificially forcing it split into multiple sections when you can just develop it in one cohesive unit using the most powerful one?


Well partly because React is not that fast, and things like incorporating CSS animations are not particularly easy.

I appreciate FB is working on improving these areas, but original point is that maybe a lot of this optimization would be unnecessary if worked with the browser capabilities vs outside it in JS.


Its batch DOM writes of virtual DOM diffs ends up being a lot faster than previous SPA development models which can be further optimized with Pure Renderer. It has room for improvements but that doesn't invalidate React's approach.


Its batch DOM writes of virtual DOM diffs ends up being a lot faster than previous SPA development models which can be further optimized with Pure Renderer.

Sorry, but that isn't necessarily so. React is a lot faster than many of the other front-end frameworks, but that's because most front-end frameworks are horribly, horribly slow. However, all that rerendering and DOM diffing isn't free, and React can easily still be much slower than applying manual DOM updates if you have the patience and accuracy to write the code to do them, even if you use pure renderers and write shouldComponentUpdate everywhere.


They're taking a comprehensive look at how imperative (React) or declarative-autotranslated-into-imperative (JSX) code for describing a View actually becomes that View (which is currently either (V)DOM, or some native UI toolkit with React Native).

This process occurs in browsers, libraries, and UI toolkits today; React gives you an alternative. This means that you can render in the client, render on the server, render wherever starting from the same code.


I believe the ultimate goal is web apps with 60 fps gestures and animations.


I agree. All in the name of writing code that makes it easier to do what? Not lose track of your own javascript?


As if "losing track of your own Javascript" is something that:

a) does not happen

or:

b) is OK?

Might as well have written your sneer like: "All in the name of writing code that makes it easier to do what? Simplify development?"


Well it doesn't simplify development and that's the point, it's not a clean separation of concerns. It defies the whole purpose of using CSS, the DOM API and keeping your javascript's structural patterns cohesive. This is why Webcomponents are now part of the living standard. The browser runtime nullifies whatever React was trying to achieve.


>Well it doesn't simplify development and that's the point, it's not a clean separation of concerns.

On the contrary, it's very clean.

The real separation of concerns is between business logic and view code, and React does that perfectly.

Not between HTML, CSS, DOM etc which are artificial inflated concerns due to how the browser ended up as an ad-hoc application coding platform (from it's "document" viewer beginnings, which is where the "D" in the DOM comes from).

(And of course nothing stops you from using CSS and external styles with React, separating style from behavior).

>This is why Webcomponents are now part of the living standard.

Web components only solve the non-interesting parts of what React does. Namely, isolated components. All the state and management mess for the entire app is still yours to deal with. Even React alone does more, nevermind React+Redux/FLUX etc.

Which is also the reason React caught like wildfire, and nobody much cares for Webcomponents (e.g. not any statistically significant numbers).


I generally agree with your position here, but I think you're giving React a bit too much credit for separating business logic and view code. In practice, anything complicated probably requires shouldComponentUpdate for acceptable performance. Writing reasonably efficient shouldComponentUpdate in turn requires underlying data that can be compared quickly, hence for example the current interest in immutable data structures that can be tested for equality by checking a single reference. And so the choice to use React for rendering does have implications for how the underlying data is stored as well, which undermines any claims about truly separating the view logic from the business logic.


Sure, all abstractions are leaky one way or another, but in the end React gives you much better separation than what we had before.

Having to deal with shouldComponentUpdate is a blessing compared to having to juggle 4-5 different concepts and web technologies, plus manage state, plus separate logic yourself, etc.

Heck, in Backbone, which is as bare as it gets, and you needed to wrap your data in specific classes...

And that's IF (and it's a big IF) you have some very complex performance case. In most cases I never needed it, and tons of stuff can just be a pure render function.


Again, I generally agree with your comments here. I just think it's important to point out that this particular leak exists, because a lot of React advocacy completely glosses over the point. The need to have a data model that supports quick diffs one way or another has profound implications for the scalability of your front-end code and it's an architectural decision that will be expensive to change later if you get it wrong initially and learn that the hard way.


Not lose track of your own javascript?

No, not lose track of the current state of your DOM.


[flagged]


Your rant says nothing of substance other than a wall of text asserting it's "a horrible, horrible idea" without backing it up with any technical merit. React has proven simplicity and performance benefits and its one-way data flow architecture is optimal for developing large, complex web apps as it just lets you focus on what your App should look like for a given state and React takes care of batching the most optimal batched DOM mutations to transition your App into the next state.

Working directly with the DOM means imperatively mutating it in-line that forces you to become a manual book keeper to make sure your App state and DOM mutations stay in-sync. It's slower, forces flow/layout thrashing at inopportune times, more tedious to maintain, harder to debug and visualize your App's state, etc. There's a reason why the world and all major SPA fx's has moved on from jQuery, you're clinging on to the past JS development model.

> Use ES6, look at how to properly use HTTP, browser networking and server-side events

You're dropping technology labels that has absolutely nothing to do whether you're using React or not. I suggest you learn React before asserting it as "the dumbest idea any frontend architect" - it's likely the future development model for any UI fx with React Native the most popular Github project last year and Microsoft and Ubuntu adopting it for their latest native UI fx's. It continues to be adopted by large tech companies which they're using to rewrite their large code-bases for the development and end-user benefits it provides over previous development models.


Wow. I am clinging to the past JS development model? I said nothing of technical substance? If you want to develop a large and "simple" application look at Aurelia. The whole point of a web app, large or small is to keep it simple.

What you're misunderstanding is the basic foundations of solid software principles. Popularity does not equal tried and true. That's not logical. I understand React, or else how could I possibly nail it to the wall? You assume I use some sort of JQuery paradigm to develop UI applications, that a pretty presumptive claim on your part and it is absolutely not true.

>Working directly with the DOM means mutating it in-line and your state and you have to become a manual book keeper to make sure your App state and DOM mutations stay in-sync. It's slower, more tedious to maintain, harder to debug and visualize your App's state, etc. There's a reason why the world and all major SPA fx's has moved on from jQuery, you're clinging on to the past JS development model.

No, this is not what it means, this is your opinion. What do you think you're doing when you manage the state of a React component? If you cannot debug your app and understand its and runtime state, you need to look at your complexity bottlenecks. The browser runtime is an event-driven framework. Custom events avoid implicit calls and runtime race conditions.

What I am clinging to is the living standard and a clean separation of concerns in software development. I am standing on the shoulders of giants. I cannot help what choices developers make and what shortcuts they make to understand the browser's inherent technology. I've actually built enterprise SPAs and I have been doing it for the last 16 years, since the DOM was actually introduced.

Decompose React yourself. I've laid out my argument. It's not a rant, it's reality. React may have attractive advantages, but I don't think its adoptees understand the seriousness of the trade-offs they're making.


Sorry, you haven't laid out any argument.

You need to look into what separation of concerns really is and isn't. Switching back and forth between your highly coupled data model and view is not separation of concerns.


> Wow. I am clinging to the past JS development model? I said nothing of technical substance?

Yes and this reply hasn't got any better, which mainly consists of dumping meaningless cliche's that are meant to sound clever but have very little connection in justifying any of your assertions.

> What you're misunderstanding is the basic foundations of solid software principles. Popularity does not equal tried and true. That's not logical.

Case-in-point, this is a very weak and transparent argumentative style. Focus on technical merits not dumping meaningless cliches which only adds negative value to your argument. I can already tell the rest of your comment is going to have very little substance.

> I understand React, or else how could I possibly nail it to the wall?

You haven't done anything of the sort, your baseless points shows the exact opposite that you have no idea how React works or the benefits it provides.

> You assume I use some sort of JQuery paradigm to develop UI applications, that a pretty presumptive claim on your part and it is absolutely not true.

Then show something else where modifying the DOM directly offers a better programming paradigm as you've claimed. jQuery at least made DOM mutations bearable, which was a much better improvement than what was available before it.

> If you want to develop a large and "simple" application look at Aurelia.

Yeah that's an example of another non-jQuery modern SPA that saves you from modifying the DOM directly.

> The whole point of a web app, large or small is to keep it simple.

No the point of a web app is to deliver value for its intended purpose, the benefit of a FX is to manage complexity which React's declarative one-way data flow architecture lets you do by leaving you to just focus on how your App looks for any given state instead of handling all the imperative mutations for implementing your App's functionality and all its interim DOM state, which is what old-school development of modifying the DOM directly forces you to do. This doesn't scale for large Web Apps and is one of the reasons why React has become so popular.

> What do you think you're doing when you manage the state of a React component?

Exactly what it says, you're just managing your Apps state, React takes care of batching the required DOM mutations so the DOM matches the declarative view of your App's component.

> If you cannot debug your app and understand its and runtime state.

You can absolutely inspect your Component state at any point in time, which React excels at as you only need to look at your App's state and not the state of the DOM which is much harder to debug/analyze/maintain.

> you need to look at your complexity bottlenecks

You need to lookup complexity bottlenecks

> The browser runtime is an event-driven framework. Custom events avoid implicit calls and runtime race conditions.

More factoids that does nothing to serve your argument. Seems you're just looking for spaces to shove meaningless points in.

> What I am clinging to is the living standard and a clean separation of concerns in software development.

Imperatively mutating the DOM suggests otherwise. You come off as clinging on to old school development and are fearful of any new development paradigm that threatens your existing knowledge.

React separation of state and view and easy encapsulation offers the ideal componentization model. Encapsulation and easy composition are vital in building large Apps composed of isolated and reusable components.

> I am standing on the shoulders of giants.

Another disconnected cliche, you're now resorting to using blind faith to guide your thoughts rather than any sound technical points or are able to offer any alternatives that show where something else is comparatively better - deflecting it now as: it's different to what was built before, so must be bad.

> I cannot help what choices developers make and what shortcuts they make to understand the browser's inherent technology.

You should make an effort to understand what value a technology provides before you can discount it and you should definitely have in-depth knowledge about something before you can discredit it.

> I've actually built enterprise SPAs and I have been doing it for the last 16 years, since the DOM was actually introduced.

Doesn't sound like you know what an SPA is, which was only coined in 11 years ago that only became popularized and a viable choice after JS VM's got fast. "Enterprise SPAs" would be the last place they were being adopted in any meaningful way. The years you've spent using old-school technologies is likely contributing to your fear of considering alternative development models.

> Decompose React yourself.

I've already developed several React Apps after having tried all leading JS FX's - I consider React by far the best development paradigm for building large SPAs (and UIs in general) as I have a preference for its small, but very powerful surface area. React/Redux lets you focus on a higher class of abstraction making it trivial to build certain classes of Apps that would otherwise take an order of magnitude more effort, leaving you with a much more complicated and harder to reason about code-base.

It may not be your preference which is fine, but you should have actual reasons before discrediting it.

> I've laid out my argument. It's not a rant, it's reality.

You've really not laid out any arguments, just baseless statements without justification.

> React may have attractive advantages, but I don't think its adoptees understand the seriousness of the trade-offs they're making.

Yes React's development model has several advantages, and I'd expect the teams putting in the effort and investment to rewrite their large JavaScript code-bases know exactly the benefits it provides, given their experience with short-fall of existing technologies.


lol dude, you're a riot. Have a discussion. How far you want to drift away from the issues that have been laid it is not a discussion. Everything you write is just one big red-herring and the proof of that is laid out right on this thread.


There are direct responses to each of your baseless assertions. You've provided no proof and its your meaningless cliches that are the red-herring, likely used to cover up your lack of knowledge about React and SPAs in general. Walls of text that's not close to demonstrating one iota of proof.


I couldn't care less what's going on under the hood. I use React because it's a delight to work with. It has completely changed the way I write web apps. You should try it.


That's why we write in C# or Java instead of C and machine code. We accept abstractions at the cost of more computations in exchange for maintainability and reduced complexity.

React is similar to how innerHTML became more popular than appendChild and createElement.

In fact, I could almost say React is innerHTML for the web, without the negative effects.


Have you actually used React to create a web application?


React's popularity makes it popular target for (sometimes uneducated) criticism. JSX is one of common targets. Library's size is other. Misconception that its just VDOM is another. And then there's popular FUD about how FB may nuke your project on a whim due to patent clause in its license.


It's hard to believe people say so much random bad stuff about React when it actually has a really good track record with developers and companies and various scales.


Do you actually understand how it really works?


I'm curious, answer my question. You sound like someone who's making a argument based on zealotry instead of pragmatism.


You mean besides the one where I learned it and realized I would never use it in production? No, and here is why:

1. There is no adherence to the living standard

2. Web components are meant for this exact purpose

3. The added complexity and burden on the browser runtime will only create headaches as the application begins to scale.

4. There is no clean separation of concerns.

5. Writing HTML in js files is an anti-pattern.

6. The browser runtime, CSS and DOM obviate what React is trying to accomplish, especially with web components being added to the living standard.

7. Browser networking, workers and server-side events are much more powerful ways to scale complexity.

8. CSS3 is not hard to understand.

9. There is no way to bypass the browser's rendering engine.

10. The business scenarios for our software product did not align with the use of React after a very thorough ATAM.

11. Much better technologies exist that do not cross-cut concerns the way React does. Aurelia is what I ultimately recommended because it did not violate points 1-10.

React isn't pragmatic and if anything, the lack of examination of its internals distinctly reflects the zealotry of arguments that oppose reasonable points. Every dissenting argument I have ever encountered, especially the ones on this thread are rationalizations and opinions. I haven't seen one technical advantage that solid software engineering, the browser API, and HTTP do not already provide.

Discussions like this are meant to become arguments based on facts, zealous or not. As always, fact trumps opinion.


> 1. There is no adherence to the living standard

Do you mean the HTML living standard? Why would a javascript library be concerned with the HTML standard? What do you mean with this? The HTML output from React certainly complies with the living standard, and it doesn't even have any artifacts now that react-ids have been removed.

If you meant the javascript rolling standards, React pioneered the use of many ES2015 features.

> 2. Web components are meant for this exact purpose

Web components are meant for encapsulation, a problem that React handles fairly poorly. Meanwhile, React's alleged purpose is to handle developing large applications, a problem that web components do not really address.

> 3. The added complexity and burden on the browser runtime will only create headaches as the application begins to scale.

Practically every abstraction adds complexity and "burden" on the runtime - even Web Components! This is an assertion without evidence. There's a contention line between performance and development time that, for web applications, is usually skewed heavily towards the development side. You need to deliver your web applications in a short time frame, and also continually update them. These are the things React alleges it excels at, while also delivering acceptable performance.

> 4. There is no clean separation of concerns.

React has three clearly separated parts, component definitions, VDOM rendering and reconciliation. Which concerns aren't separated?

> 5. Writing HTML in js files is an anti-pattern.

React discourages writing HTML in js files. The standard method of using React does not involve writing HTML, React renders that for you.

> 6. The browser runtime, CSS and DOM obviate what React is trying to accomplish, especially with web components being added to the living standard.

This is just word salad. How does the browser runtime help with developing large applications?

How does CSS? Just look at all the CSS frameworks trying to wrangle the complexity of managing CSS in a large application - from CSS parsers like less and sass to naming styles like BEM, CSS modules, and so on.

The DOM isn't concerned with writing large applications at all, however directly manipulating it is usually a minefield thanks to its API and forced re-renders. Pretty much every JS framework has run away from the DOM.

Web Components don't really tackle the problems building a large application.

> 7. Browser networking, workers and server-side events are much more powerful ways to scale complexity.

I don't know how any of these things help with complexity. They're performance optimizations.

> 8. CSS3 is not hard to understand.

This is not an argument against React, since React components use CSS..

> 9. There is no way to bypass the browser's rendering engine.

Thus, we should never write libraries and frameworks for rendering? What is this even an argument for?

> 10. The business scenarios for our software product did not align with the use of React after a very thorough ATAM.

That's fine, but that's a consideration you make for yourself. It doesn't make React "quite possibly the worst anti-pattern". This is the first reasonable argument you've made.

> 11. Much better technologies exist that do not cross-cut concerns the way React does. Aurelia is what I ultimately recommended because it did not violate points 1-10.

This is possible, I haven't used Aurelia to comment.

React is very pragmatic for me. I've been moving towards data-driven UI rendering ever since I started web development. The components have good lifecycle hooks, unlike angular 1's directives. The VDOM rendering frees me from touching the DOM(a huge plus for me), and I've never had to wrestle with its edge cases(don't really do a lot of animation). The diffing engine makes it absolutely fast enough for any app I've written. The combined coding style(don't store state in the DOM, render the UI from state, take props instead of locating data via global services) is a great fit, I've already tried to enforce all these for my team manually. The documentation is top-notch, there's tutorials for everything. The tooling for it is just great. The debug story just makes me happy. Debugging React apps is a breeze compared to any other app I've had to debug. This is probably the biggest selling point for me. I am willing to go through quite a bit more pain than React causes to get this kind of debugging.

React for me has some fundamental problems, like its small surface area(only handling the view), which means it doesn't solve all my problems. The things I use it for though, I'm really content with.


> This is possible, I haven't used Aurelia to comment.

I took a brief look at the documentation. It appears as though it's a "batteries included" framework favoring convention over configuration, with a custom templating specification a la AngularJS.

The nice thing about React - to me - is the straightforward mapping of Javascript control flow to DOM. You don't have to learn a custom templating protocol in order to render things and it's ridiculously easy to create encapsulated components.

data.map((el) => <div>{el}</div>)

var Foo = React.createClass({render: () => ...});

Gets you <Foo/>

Even less syntax noise if you take advantage of stateless functional components. [0]

Compare this to Angular's ridiculous directive declaration syntax nightmare... cringe :)

Aurelia isn't that much better in this regard [1]

There's a bunch of boilerplate that needs to be introduced for you to create simple custom elements: lots of .bind, <require> tags, separate files for each custom element. Bleh :)

Maybe it's better when you're working with a bunch of developers with bad habits, or have to grok a huge code base. There, I can see some of its conventions and structure coming in handy. Still, I don't see why OP is throwing a hissy fit over it. Everyone has their favorite tools ¯\_(ツ)_/¯

0. https://facebook.github.io/react/docs/reusable-components.ht...

1. http://aurelia.io/hub.html#/doc/article/aurelia/templating/l...


> React for me has some fundamental problems, like its small surface area(only handling the view), which means it doesn't solve all my problems.

I've occasionally, successfully repurposed React to keep track of my AJAX requests. Just create a (<div/>) component for every type and start/cancel the XHRs via componentDidMount() or componentDidUpdate().


What is the "incremental rendering" that this article is talking about?


It's rendering part of the virtual DOM in one cycle, rather than the full thing. This goes hand-in-hand with the ability to prioritize the rendering of different components.

For instance, when you're scrolling through a large table, you may want to prioritize the rendering of a custom scroll bar over the rows themselves. With the Fiber architecture, you can do that so the scroll bar can hit a responsive 60fps and the rows can fill in when there are spare cycles.


Thanks!


Does it strike anyone else that the entire battle cry of react reeks of pre-mature optimization?

Let's load a giant javascript framework, slow our onload and page ready event by half a second, overcomplicate our build infrastructure with JSX, mixing up our declarative code with non-standard imperative/functional javascript and HTML, start importing sass and CSS into our javascript files, and use an API that is weird and borrowed (componentDidMount?).

What exactly is the savings here? I fail to see it. When and if you have 100,000 DOM elements on a page and need to do efficient rendering and reconciliation of what has changed? Poor code organization? Adherence to a weird and clunky API? Because Facebook does it?

I'm sorry but I've had the displeasure of working on a few apps where developers have used React and I could have done the same thing, without all the bloat, achieving much faster performance, both measured from first byte to when the page was ready for the user to use, to any interactions on the page. All of these apps were relatively simple single page apps.

What has happened to us as developers that this sounds like a good idea? Whatever happened to pragmatism? Has that just lost by the wayside of the new shiny?


It isn't so much pre-mature optimization rather than having the next step of the evolution of modern webdev.

Let's go back 6 years in webdev land. jQuery was king, Angular was the up-and-comer. You have a fairly complex jQuery site probably rendering most things from ruby or php. The only way to debug it was with console.log and refreshing the page.

Angular comes around introduces modules and unit-testing, cool! You hook up grunt and protractor, you install angular batarang. Everything is good. But you end up building this huge angular app. You try to debug this edge case when you have this panel open under this tab. You get frustrated that you have to click on the same things over and over again. Livereload can inject css but not js. When you change the html of your angular directive you have to reload the page too.

This is where React comes in. React + Redux + Webpack makes it such that you can apply livereload to _everything_. The css that your component imports, the html it renders, what actions happen when you click a button. Everything. It's not necessarily the new shiny rather than just the next step to making things easier for devs. It gets out of your way so you could focus on styling, structure and business logic.


Exactly! Not to mention the reusability benefits of components - rather than passing around JQuery selectors and objects.

The cognitive load of using plain React is unparalleled for me. The effort to setup the tooling is a bit of a hassle though..


> It's not necessarily the new shiny rather than just the next step to making things easier for devs

It's more testable, maintainable and reusable, but easier certainly not.


And the next logical step for styling IMHO is using tachyons.css, or the port: react-native-style-tachyons.

It frees you from the organsation of a stylesheet and from having to find widths, heights, paddings, margins and font-sizes that work together.


> What exactly is the savings here? I fail to see it.

Huh? Did you read the article? One answer (which as a React user I think is the main one) is right there. To quote them,

> The central idea of React's API is to think of updates as if they cause the entire app to re-render. This allows the developer to reason declaratively, rather than worry about how to efficiently transition the app from any particular state to another (A to B, B to C, C to A, and so on).

If you disagree with this, you should explain why.


It sounds like you worked on a few projects where people reached for a JavaScript framework when it wasn't necessary; I can understand how that can be frustrating. But surely you aren't saying that there isn't any room or merit for front end frameworks at all?

By front end framework standards, react isn't giant at all. And in terms of internal complexity, most people using react don't even have to know about any of the things in the post

I think it may be helpful to consider the possibility that there exist people who are more rational, pragmatic, and intelligent then you or I, who think React is useful for certain types of work. Assigning the motivation of "chasing shiny things" to people liking something you don't will be detrimental to gaining further understanding


More than once I chose to use React (+ Redux, etc.) for something that could've been solved with a few snippets of jQuery or even just plain javascript.

In many of these cases the app ended up becoming complex enough that I was happy to have prematurely optimized. This has happened often enough that I tend to give React the benefit of the doubt when I'm building an app. (This is also the reason why sometimes I choose to use batteries-included Rails even though Express.js or some lighter framework seems like a perfectly fine choice.)

In other cases using React didn't make things easier, but doing so was convenient because I'd been working with React most of the time anyways (and had some other project to use as a basis or even entire components I could re-use).

All that said, I do err on the side of shiny sometimes, and spend much more time (and Kb's) using React for something where it wasn't necessary. So I see your point.


It's no longer considered premature optimization when you have 100,000 DOM elements on a page, like Facebook conceivably would. It's not surprising that this project comes from them.

Does a run-of-the-mill JS app require React? No, there are hundreds of alternatives from direct state mutators like jQuery, all the way through full MV* frameworks like Angular, Ember, Backbone, or newer.

React is cool and innovative in its problem domain, but not all users of a technology will use it solely on its merits. This is frankly a risk with any 'popular' technology.


You might want to re-read your comment. Your argumentation is only relevant for grossly over-engineered projects.

React isn't about the number of elements on the page or the performance, it's about making it possible to build the UI in a declarative way. It raises the barrier of entry but immensely improves clarity, testability and maintainability.

If you ever work on a non trivial frontend with people who are well versed in the React stack and functional programming, you're in for a ride full of amazement.


The best thing about React / Relay / GraphQL is the emergence of the idea of using a graph query language. Will GraphQL be the ultimate winner? I don't know. But I suspect this approach will catch on, since the problems with RESTful interfaces are well known, and painful enough to force a change. And yet, once we start using GraphQL, the other technologies get dragged along with it. We want pagination so we use Relay. We want immutability on the fronted, so we use React. It's a powerful combination, though I can imagine the ideas being copied by other frameworks, who perhaps offer a cleaner implementation (my biggest grip with GraphQL is the verbose mutations).

http://www.smashcompany.com/technology/graphql-is-the-best-t...


It's a tightrope. Their are plenty of arguments to be made for having a large build system that makes development easier/more conventional. Their are also arguments to be made for minimalism and sticking to the fundamentals of the web with plain html/css/js.

What we can all agree on is that its good to at least have the CHOICE of development environments, build systems, and ecosystems. And I personally always fall back on: "this complexity is why I get paid more then most people".


>And I personally always fall back on: "this complexity is why I get paid more then most people".

This is pretty cringeworthy. If your tools are introducing enough incidental complexity that it needs to be reflected in your compensation, i'd argue your tools are failing your company badly.

You should be paid more to reflect a higher level of technical or domain expertise relative to other engineers, not to account for your ability to glue together a mish-mash of poorly documented and half-baked technologies.


I don't write tools that are unnecessarily complex in order to make more money.. I get paid to use tools that are necessarily complex, and use them properly. How you interpreted my post to relate entirely to the former is beyond me.


Just built our first major react/redux site. Moderate complexity, I'd say. React runs pretty fast, but on page load we take 2.5s to compile all the JavaScript.


Are you sure compilation is the bottleneck? 2.5s seems way too much by an order of magnitude.

Have you looked into compiling during your build step instead of at runtime?


In a large application my rule of thumb is 1/3 compile, 1/3 React internals (which includes DOM updates) and 1/3 product code. 2.5 seconds is a lot, but not surprising if an application is being shipped as a multi-megabyte bundle.

Compiling as a build step doesn't get you very far when you are forced to ship source code to JS engines.


I guess I may be a bit confused on what he meant by compilation

Since JS is JIT compiled, I assumed perhaps he was delivering his scripts in raw JSX+ES6 and transpiling at runtime via babel's browser.js (as shown by react's Getting Started guide) [1].

If he meant time spent parsing the JS then I'd be a bit suspicious about the 2.5s both because of the extraordinary length and also I find it hard to believe someone who would know how to measure parse time would mistake the term with compilation.

[1]: https://facebook.github.io/react/docs/getting-started.html


I have worked on several react native projects. The more I do the more I'm convinced you are correct


Could you elaborate on that? My experience with React has been that most of the 'shiny time-waste' problems don't arise from, say, React + Redux, but from the itch to use all the 'cool stuff' that people are talking about.

I've wasted so much time configuring apps to get hot module reloading to work, adding all sorts of redux middleware, using react-router as it transitioned to a completely new react-router, working with higher order components, using some immutable library, etc.

Many of these things were not necessary for the stuff I was building. In fact, in a bunch of cases I could've just used React and nothing else. I suspect if I'd done that, it wouldn't have felt as much like premature optimization.

Thankfully most of these projects were personal, and learning a lot about the React ecosystem has been fun. Still, lots of premature optimization.

I'm very curious to hear where you ran into issues.


I wouldn't say that React is particularly huge compared to other frameworks. Certainly when if first came out it was actually quite small. I haven't checked lately, but I think it is still considerably smaller than things like jQuery.

But you answer your own question in the second paragraph. Why use React? Because you want to use a non-standard functional style of Javascript. For me, it's a pretty big advantage, but if you don't like functional style programming and can't deal with persistent, immutable data structures, then I think you would be wise to avoid React.

To a certain extent I can sympathise with your feeling. Almost every time there is an article linked here on HN I see people getting into trouble with React. Usually the solution they reach for first is to strap on more plugins (with Flux, etc). Often the structure imposed by those plugins help them be more disciplined, improving their code, but at the cost of added complexity.

React itself is very simple. The trick is in understanding how to use it. Things like componentDidMount are useful for very strange corner cases, but it is pretty common to see people use it in every single component they write. If you pull componentWillReceiveProps, etc out of the box, then it should be a gigantic clue that you have done something very, very wrong. Mostly there are warnings in the documentation about this. Mostly people ignore/don't read them ;-).

JSX is really a non-issue for me. Personally, I don't understand why anyone would want it. You can write exactly the same code without JSX and it looks pretty much exactly the same (except with lots of insane, silly parentheses -- but, we're here for the functional, right?). Whatever. Normally I have to browserify my code anyway. Adding another step to the build is not exactly rocket science. I'm also usually using either coffeescript or ES6 through babel, so I've got a compile step either way. The times where I insist on no JSX is when I'm doing ES5 work and want to run unit tests in Node without the compile step. But that's pretty rare.

Having said all that, I'll take the opportunity to offer you some advice. I don't know if you are in the mood to receive it, so it might be fruitless. You said:

> Whatever happened to pragmatism? Has that just lost by the wayside of the new shiny?

One of the things about smart/talented developers is that they are used to growing up thinking that they know the right answer. I was certainly of that mould. As I've gotten older, though, I've realised that this way of thinking is self-referential and ultimately limits your growth.

In this case, I think you've decided apriori that the way you are comfortable doing development is already the best -- or at least so much better than what you see elsewhere that it doesn't matter if it's the best. When you see people struggling (and failing) with something new and unfamiliar, the natural inclination is to assume that it is no good.

Did you know that back in the day, many programmers thought that MFC was an exceptionally good idea? Anybody forced to use that anachronism now would probably quit on the spot. Things do get better over time and new frameworks and techniques can improve our lives as programmers. While it is pragmatic to stick with what you know, you have to balance that with learning new ideas that make you a better programmer.

Humility has always been something I struggle with, so perhaps I am the wrong person to say anything. However, when you see someone making the same mistake that you made over and over again, it behoves one to speak out, doesn't it?


So how does React know which parts of the model need reconciling, without traversing the complete model and/or the complete state on every update?


When you call setState on a component, only that component's subtree is reconciled and re-rendered.


That's in the virtual DOM. React will diff the VDOM and browser DOM and only render actual differences.

The React API will also let a component decide for itself if it should be rendered.


Okay. But how do you know what components to call setState on then? Is state spread over components, or is it stored centrally?


setState is a public API, usually triggered in response to a user event like a click or an input change event.

State in React is local to a component, but it can be passed down to a component's children in the form of props.

Centralized state can be achieved using a library like Redux, where an individual component subscribes to an external data store's changes. Redux abstracts the details away, but under the hood it's still just setState.


Has this something to do with Preact, which started as an animation experiment and became a React alternative?


No, not related.


And I clicked this thinking it was some competitor to Google Fiber, to describe their networking architecture.




Guidelines | FAQ | Support | API | Security | Lists | Bookmarklet | DMCA | Apply to YC | Contact

Search: