11 ms·
React Fiber Architecture
- Bahamut 10y agoThis 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.
- acdlite 10y agoI 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.
- Bahamut 10y agoThe 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).
- spicyj 10y agoacdlite 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).
- Bahamut 10y agoThanks 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.
- mikekchar 10y agoWow 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...
- yoshuaw 10y agoYes, 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
- amelius 10y agoSo how does React know which parts of the model need reconciling, without traversing the complete model and/or the complete state on every update?
- acdlite 10y agoWhen you call setState on a component, only that component's subtree is reconciled and re-rendered.
- rukuu001 10y agoThat'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.
- deleted 10y ago[deleted]
- amelius 10y agoOkay. But how do you know what components to call setState on then? Is state spread over components, or is it stored centrally?
- acdlite 10y agosetState 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.
- k__ 10y agoHas this something to do with Preact, which started as an animation experiment and became a React alternative?
- spicyj 10y agoNo, not related.
- gedy 10y agoThis 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?
- Ralfp 10y agoCould 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.
- sarahappleseed 10y agoI agree. All in the name of writing code that makes it easier to do what? Not lose track of your own javascript?
- coldtea 10y agoAs 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?"
- kensign 10y agoWell 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.
- coldtea 10y ago>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).
- iamleppert 10y agoDoes 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?
- tootie 10y agoJust 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.
- cheapsteak 10y agoAre 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?
- underwater 10y agoIn 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.
- jiaweihli 10y agoCan 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/ http://rivetsjs.com/
- spankalee 10y agoI'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
- eatbitseveryday 10y agoAnd I clicked this thinking it was some competitor to Google Fiber, to describe their networking architecture.
- toomim 10y agoWhat is the "incremental rendering" that this article is talking about?
- timdorr 10y agoIt'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.
- toomim 10y agoThanks!