13 ms·
React Implementation Notes
- amelius 10y agoI'm wondering about something. Let's say I have a listbox with N elements, and one element is appended or changes state. Will the reconciler have to perform O(N) work for these operations? If elements are added one by one, will the reconciler have performed O(N^2) operations by the time the last element was added?
- spicyj 10y ago1. If a component changes state and its parent doesn't, then the other children aren't considered so it would be O(1). If the parent rerenders, then yes, we would consider each child and it would take O(n). 2. Yes, it would. You would really have to go out of your way to make that happen, though. React has a feature for batching state updates together to prevent unnecessary rerenders if all of the updates occur together. Beyond that, it's rarely an issue. If you have a particularly long list you can use a tool like react-virtualized (https://github.com/bvaughn/react-virtualized https://github.com/bvaughn/react-virtualized) so that only the onscreen rows are rendered at all.
- freditup 10y ago> You would really have to go out of your way to make that happen, though. React has a feature for batching state updates together to prevent unnecessary rerenders if all of the updates occur together. These batched state updates only happen "within React's walls", right? So for example, say you had an RxJs observable that omitted a list of items to display. When you first subscribe, it emits say, ten items, one by one, but all in the same browser tick. It may emit items later in the future as well. In this case, each of the initial emitted items triggers a full rerender and you get the O(N^2) behavior, correct? My point here isn't that this is the end of the world, but just that it isn't that crazy to say that it might happen.
- spicyj 10y agoYes, you're generally correct. If you can call into ReactDOM.unstable_batchedUpdates at the top of the stack, that's another approach. We might be able to make that the default in the future so synchronous calls are always grouped even if React isn't on the stack. We generally see the most success when you update your data wholesale with the latest copy from your stores, but your RxJS example is a good one.
- deleted 10y ago[deleted]
- Wintamute 10y agoAwesome that these implementation notes are so simple and laid out over just a few pages. Speaks to the conceptually simple underlying model of React I think. Nice job.
- joshmarinacci 10y agoI really appreciate getting an inside look at complex code like React.
- tambourine_man 10y agoBuilding React From Scratch: https://www.youtube.com/watch?v=_MAD4Oly9yg https://www.youtube.com/watch?v=_MAD4Oly9yg
- ggregoire 10y agoBravo to the React team for the work during the last few months! It's truly amazing, specially for the new users. Among other things: 1) Create-React-App[1]: Lets everyone starts a React app with Babel/Webpack (JSX, classes and import/export) without any knowledge about Babel/Webpack. 2) The new Contributing docs (Codebase Overview, Implementation Notes (discussed here) and Design Principles) offer a starting point to figure out how React works. 3) A revamp of the current documentation is going to be released soon[2] 4) "You might not need Redux"[3] --- [1] https://github.com/facebookincubator/create-react-app https://github.com/facebookincubator/create-react-app [2] https://github.com/facebook/react/pulls?q=is%3Apr+is%3Aopen+label%3A%22Component%3A+Documentation+%26+Website%22 https://github.com/facebook/react/pulls?q=is%3Apr+is%3Aopen+... [3] https://medium.com/@dan_abramov/you-might-not-need-redux-be46360cf367#.f1q1ro20m https://medium.com/@dan_abramov/you-might-not-need-redux-be4...
- guscost 10y ago> 4) "You might not need Redux"[3] For some older projects I found a hand-built flux helper[0] of ~220 lines worked great and didn't require any toolchain modifications. The switching costs to some of the ES6 stuff was too high in that case, but it's also a potentially leaner app if you don't need the advanced features of Redux and ES6. The Redux architecture is so nice though. [0] https://github.com/guscost/simple-flux https://github.com/guscost/simple-flux
- Etheryte 10y agoRedux is just a fancy pubsub.
- chrislloyd 10y agoOr less fancy depending on how you look at it.
- cel1ne 10y agoI think redux got 50% right and 50% wrong. 1. good: having a sideeffect-free, serializable application state. That concept can also be used in mobile apps for easy pause/resume. 2. good: being able to render that state from one parent, because you don't need to manage two separate statemachines (the UI and the business logic) anymore. 3. bad: shoe-horning all state-transition into functions/reducers. Fp is awesome, but sometimes imperative constructs are more appropriate, especially in a mostly imperative language. Use fp where it feels natural, not everywhere. 4. bad: shoe-horning everything into immutable data-structures. Seriously, when did newName => { this.name = newName } become (state, newName) => { return state.set("name", newName) } ? Just change the state. If you want to prevent errors, freeze and seal your state. If you want time-travelling debugging, copy it via serialization. No need to slow down production code by copying and throwing away data all the time. 5. bad: using Immutable.js, thereby slowing your code down by two or three orders of magnitude. And I guess losing many GC and JIT optimizations by throwing out different types of objects and pressing everything into the generic map-structures, that immutable.js uses internally) I wrote multiple sites/apps using immutable and redux, but i'm back to pure react and lodash. Code is more concise, simpler and way faster, even though componentDidUpdate has to use lodash's _.isEqual instead of a simple comparison.
- jpolitz 10y agoPart of these notes, Fiber [0], reminds me of a half-joking "corollary" to Greenspun's Tenth Rule (credit @shriramkmurthi): Any sufficiently complicated JavaScript program contains an ad hoc, informally-specified, bug-ridden, slow implementation of delimited continuations. Control over continuations and the stack is our main compiler and runtime engineering hurdle in Pyret. Projects like Doppio [1], WeScheme [2] and GopherJS [3] go through staggering amounts of overhead and effort to get pausable, resumable, and stoppable computation in the browser environment. I'm excited to see how this develops in React with fiber. It's much more application-specific, but it's the same underlying problem. [0] https://facebook.github.io/react/contributing/codebase-overview.html#fiber-reconciler https://facebook.github.io/react/contributing/codebase-overv... [1] https://github.com/plasma-umass/doppio https://github.com/plasma-umass/doppio [2] https://cs.brown.edu/~sk/Publications/Papers/Published/yk-whalesong-racket-browser/paper.pdf https://cs.brown.edu/~sk/Publications/Papers/Published/yk-wh... [3] https://github.com/gopherjs/gopherjs#goroutines https://github.com/gopherjs/gopherjs#goroutines
- ilostmykeys 10y agoWhat about generators? I've built coroutines based on generators. CSP has been implemented in JS using generators. Not sure why those projects went thru "staggering amount of overhead" to get what we get for free with generators. Please educate.
- 1propionyl 10y agoBecause generators may be implemented with delineated continuations but they are not themselves the same thing.
- ilostmykeys 10y agoAre you sure it's not because those frameworks/libraries were written before generators became available in the latest browsers? :)
- morenoh149 10y agothat's Delimited continuation
- dustingetz 10y agoI have a question, lack of dynamic scope in render functions is causing me major issues in making highly dynamic and complicated UIs in ClojureScript. I understand that Javascript doesn't have proper dynamic scope so you guys probably weren't thinking about it, but I also see you guys moving farther and farther away, there's the whole Context hacks and now the web worker call stack serialization thing. Are there technical reasons that this can't be made to work with dynamic scope? I think you lose a lot of stuff by, well, not being actual function composition, only pretending to be. cljs.user=> (ns foo.core (:require [reagent.core :as reagent])) nil foo.core=> (def ^:dynamic *foo* 42) #'foo.core/*foo* foo.core=> (defn inner [] [:div *foo*]) #'foo.core/inner ; React component call - broken foo.core=> (defn root1 [] (binding [*foo* (inc *foo*)] [inner])) #'foo.core/root1 foo.core=> (reagent/render-to-string [root1]) "<div ...>42</div>" ; Direct function call - works foo.core=> (defn root2 [] (binding [*foo* (inc *foo*)] (inner))) #'foo.core/root2 foo.core=> (reagent/render-to-string [root2]) "<div ...>43</div>" A quick example of dynamic scope: cljs.user=> (def ^:dynamic *foo* 42) #'cljs.user/*foo* cljs.user=> (defn negate [x] (- x)) #'cljs.user/negate cljs.user=> (binding [*foo* (inc *foo*)] (negate *foo*)) -43
- spicyj 10y agoI don't know much Clojure, but it sounds like this is exactly the use case that context is meant for. If you were to use dynamic scope, how would the variables be restored if one of the descendants updated via setState? It doesn't seem to me like it would work. Also, not sure what "context hacks" you mean or what "web worker call stack serialization" is.
- dustingetz 10y agoI think dynamic scope can work with setState by allocating a new closure that closes over the dynamic vars, aliasing them into lexical scope of the render function. The problem with React Context is that it bypasses the general solution offered at language layer for a react-specific solution, essentially breaking any code written without prior knowledge of React.
- garrincha 10y agoI'm a Rails developer. I work on pretty standard web apps for a living. Some more complicated than others, but still, web apps. I still haven't found a person that was able to give me a concrete reason why someone like me should invest time and resources into learning React and using it in my projects. This is an honest question, I'm not trying to be sarcastic. It's just that there are so many frameworks that come out that it's very hard to know where to invest your time.
- sim0n 10y agoFor me, once I started declaring my UI as a series of components that simply render what they are provided (the common `v = f(d)` expression), it was hard to go back to the Backbone/jQuery way of mutating things all over the place and manually updating DOM nodes to try and reflect the current app state.
- garrincha 10y agoThanks! So is react the only JS framework you use now (besides jQuery)?
- sim0n 10y agoFor view/UI, yes (if you can call React a framework). I personally do not use jQuery anymore as there is not much need to deal with the DOM directly when using React and when there is, I just use vanilla JS. Since React only deals with UI, I use it alongside a bunch of other great libraries such as Redux (for state management).
- garrincha 10y agoOut of curiosity, what do you usually use on the backend?
- sim0n 10y agoThe backend where I work (Airbnb) runs on Rails but most of my projects use node on the backend since they usually just expose a REST API. Since it only cares about UI, React is obviously not opinionated about your backend/server environment unless you're trying to do server rendering (then you need something in your stack capable of executing JS).
- mrcactu5 10y agothis is really excellent I am part of a meet-up of theorists who do build websites... but are also curious how frameworks like React work under the hood. What algorithms they use, frameworks, etc. It's possible to build a nice web-site without knowing any code at all. Or knowing some code and algorirthms. In that case the code may become very difficult to control, or revise or share with your peers. If you know some algorithms and code it's sometimes helpful to see what is under the hood.
- Ryan_Shmotkin 10y agoAlso: ReactJS: Under The Hood — ReactNext 2016 https://www.youtube.com/watch?v=xsKYAa1ZXpQ https://www.youtube.com/watch?v=xsKYAa1ZXpQ
- caub 10y agojsx makes it look a bit magical, learning React with const v=React.createElement helps also. Ex: https://github.com/caub/todo-list https://github.com/caub/todo-list
- andrewvijay 10y agoBrilliant work. Explanations like these are true gems. Kudos!