From what I've scraped together by looking through different tutorials all day, it seems like the way that react performs updates to the dom is through the following process.
User interacts with the real DOM in some way that triggers a DOM event, and the event's handler ends up fires a function that tells react to update.
React takes a "snapshot" of the virtual dom (which is also representative of the real dom at this point), and then proceeds to create a new virtual dom with the updated state and props.
React diffs the snapshot and the new virtual dom, and then only modifies parts of the dom that need to be modified to match the new virtual dom.
Is my understanding of this process correct, at least at a simplistic level?
It's almost correct, I think the mistake here is that there is no "new virtual DOM", React
always saves/uses/reuses two copies - VDOM representations of the real DOM.
(A) VDOM which helps to make changes to the real DOM (according to this VDOM, React will make the minimal changes to the DOM).
(B) VDOM which represents all changes made to real DOM (what you called a "snapshot", this VDOM will be compared to A).
So to summary the process like you did:
If VDOM does not exist, create one (VDOM A).
User interacts with the real DOM in some way that triggers a DOM event, and the event's handler ends up fires a function that tells react to update.
React creates (or reuses) one of the VDOMs (B) (which is also representative of the real dom at this point).
React diffs VDOM B with VDOM A, and then only modifies parts of the VDOM (A) that need to be modified.
React updates the real DOM using VDOM A.
Note for part 3. React uses the diff algorithm, which is somewhat just comparing the element's keys and props (shallow comparison).
Related
I understand before rendering a application reactjs creating a Copy of Real DOM as Virtual DOM and store it local memory.
Please tell me what is rendering in react js
I think ,Rendering in React is done by creating a Virtual DOM which is the copy or the blueprint of the Real DOM in simple terms ,and evrytime we made changes in the code all changes happen in the Virtual DOM instead of real DOM and then react compare REAL and VIRTUAL DOM , and when it find some node in REAL DOM which is not matching the VIRTUAL DOM it replace that node and it's children with the updated node instead of recreating the whole tree, ALL of this is know as Reconciliation i think which uses diffing algorithm
and from react v16 or v15 not sure , this Reconciliation has 2 Phases , commit and render phase which are synchronous and asynchronous respectively , means all states changes , all the side effects are done in the render phase and painting of the DOM is done in the commit phase which can't be interepted
So this is what i think how react do the rendering process in simple terms
You can get more information about react in these videos - https://www.youtube.com/watch?v=7YhdqIR2Yzo&list=PLxRVWC-K96b0ktvhd16l3xA6gncuGP7gJ
please do correct me if anyone think i am wrong or if i missed anything important about the rendering process
I understand that there are two arguments for React's Virtual DOM being faster -
It updates ONLY those elements that actually need to be updated (using diff).
It batches the updates and hence we update the real DOM only a single time. Thus the repainting is also done only once which otherwise would have been done multiple times.
I have questions regarding both these points -
As far as I know, all the modern browsers are efficient enough to update only the required elements in the DOM. For example, if I have two 'p' tags and I change the text in one of the p tags using a button click, then only that p tag will be updated by safari (I have verified this using paint flashing). So how is point 1 an advantage if it is already being implemented by the browsers?
How exactly does React batch the updates? Eventually React will also have to use the DOM api to update the real DOM. So why is that if we directly use the DOM api then the changes will not be batched whereas when React uses it then they are batched?
I have found the answer to my question.
The key is to understand the purpose of the Virtual DOM.
First we have to see what approach React takes to render the components.
Different javascript frameworks take different approaches to detect changes in the data model and render them on the view.
Consider AngularJS. When we refer to our data in an Angular template, for example in an expression like {{foo.x}}, Angular not only renders that data but also creates a watcher for that particular value. Whenever anything happens in our app (click event, HTTP response, timeout), all the watchers are run. If the value in a watcher has changed then that value is re-rendered in the UI. By running all the watchers AngularJS is essentially finding out where it needs to make the changes. The process of running these watchers is called dirty checking.
React takes a different approach. Whenever there is a state change in a React component, instead of finding out where to make the changes (like AngularJS), React re-renders the entire UI from scratch (with the updated state).
But this approach of React has a problem. To re-render the entire UI means to re-render the entire DOM tree. This is a problem because DOM updation is a slow process (due to reflow and repainting).
This is where React's Virtual DOM comes in. A Virtual DOM is just a representation of the Real DOM in form of javascript objects. It is just a tree data structure of plain javascript objects that exists in the memory. As compared to the Real DOM, rendering of the Virtual DOM is much faster because it is never rendered on the screen (no reflow or repainting needs to be done).
So how does the Virtual DOM solve the problem? When we load our app, React creates a Virtual DOM that is an exact virtual copy of the Real DOM. Whenever there is a state change in a component, instead of re-rendering the entire Real DOM, React renders an entire new Virtual DOM (with the updated state). Then it does a diff between the old Virtual DOM (the initial copy of the Real DOM) and this new Virtual DOM (rendered after state change) to find out the changes between them and it does ONLY those changes in the Real DOM. In this way, the entire UI is re-rendered (by rendering an entire new Virtual DOM) but only the minimum required changes are done in the Real DOM.
So when it is said that "Using Virtual DOM React updates only those elements that need to be updated" (point 1 in my question), it means that with the help of Virtual DOM React is overcoming the limitations of its own approach (approach of rendering the entire UI from scratch).
This answer also explains the same concept.
I have seen some answers that state that DOM manipulation using React is faster than using the DOM api because the DOM api re-renders the entire DOM tree whereas React re-renders only those parts of the DOM tree that need to be changed. This is NOT true. All modern browsers are efficient enough to update only those parts of the DOM tree that need to be changed. This can be verified using paint flashing in developer tools of browsers (also see this answer and this answer). Even if we assume that the DOM api does re-render the entire DOM tree, still this reasoning is false because the internal code of React itself has to use the DOM api to update the DOM. If the DOM api did re-render the entire DOM tree then React would also re-render the entire DOM tree because eventually it also uses the DOM api to update the DOM.
As for the second point, React actually makes batching easier for us.
In React, while the reads are done on the Real DOM, the writes (state changes) are not done on the Real DOM. Instead the writes are queued. Then when all our reads and writes have been processed, a new Virtual DOM is built based on the writes. Then diffing is done between the old and new Virtual DOM and then React writes the required changes to the Real DOM to update it. Hence eventually all the writes on the Real DOM are done together in a single reflow.
But we can manually also, without React, write our code in such a way that first all reads are done and then all writes are done. React makes batching easier because with React we don't have to care about doing the reads and writes together and React will automatically batch the writes for us. So React does not make things fast. It makes things easier.
In conclusion we can say that React is not actually faster. It is easier. As Pete Hunt says in this video, "React is not magic. Just like you can drop into assembler with C and beat the C compiler, you can drop into raw DOM operations and DOM API calls and beat React if you wanted to. However, using C or Java or JavaScript is an order of magnitude performance improvement because you don't have to worry...about the specifics of the platform. With React you can build applications without even thinking about performance and the default state is fast.".
This post by Rich Harris also states that it is a myth that "the Virtual DOM is fast".
Once React knows which virtual DOM objects have changed, then React updates only those objects, in the real DOM. This makes the performance far better when compared to manipulating the real DOM directly. This makes React standout as a high performance JavaScript library.
Regarding the Batch Update:
React follows a batch update mechanism to update the real DOM. Hence, leading to increased performance. This means that updates to the real DOM are sent in batches, instead of sending updates for every single change in state.
The repainting of the UI is the most expensive part, and React efficiently ensures that the real DOM receives only batched updates to repaint the UI.
I am not a React developer, but I am implementing a similar State and Props management infrastructure in another language. While reading about React's state management and rendering mechanism, I came across this quote
React elements are immutable. Once you create an element, you can’t change its children or attributes. An element is like a single frame in a movie: it represents the UI at a certain point in time.
If I understand correctly, every time the parent component's state changes, its children's render methods are called (if their Props was affected) and these child components are recreated and (re)rendered.
Isn't this terribly inefficient, especially if the child components involve complex computations, visualizations, etc? Is there a mechanism in React to create the components once, but update (not recreate) only the necessary parts as the states change?
Well, that's the whole point of why we use React.
Have you heard about Virtual DOM? Virtual DOM is simply a memory instance that saves the exact replica of the real DOM.
When there is a prop/state update, it does not re-render the whole thing, but only re-renders the UI parts that are affected.
So, it's very efficient and to see how they do it, you can check the source code here.
All articles I've read on React show the code when I should explicitly call this.setState() to trigger DOM update. This seems to be manual triggering of change detection. I call this.setState, React re-renders Virtual DOM and then compares it with the native DOM for changes - if anything changed, the DOM is updated. Here is the quote from the docs:
4) Every second the browser calls the tick() method. Inside it, the
Clock component schedules a UI update by calling setState() with an
object containing the current time. Thanks to the setState() call,
React knows the state has changed, and calls render() method again
to learn what should be on the screen.
Compare it with Angular digest cycle which automatically checks for binding changes and updates DOM. Although I have a way to trigger manual changed detection for a component, it's usually not needed.
My question is whether there are any cases when React triggers DOM update without requiring me to call this.setState() manually, i.e. automatic virtual DOM update?
React is a state machine that maintains a virtual representation of the DOM in memory, which automatically updates/renders (where appropriate) when this state changes.
The reason you see setState being called to trigger a rerender is because this is the most common (only?) means of updating the data structure that feeds this internal DOM representation (which will in turn feed down through the properties of children).
It's not that setState is a manual call to rerender, it's that setState causes the state to change, which in turn causes React to run a diff and update where appropriate. It's all about cascading the data to reflect the current state of your application. If that state hasn't changed then there's nothing to update, and therefore no need to rerender.
This is also why it's a very bad idea to mutate the DOM out from under React, as this more often than not results in a loss of parity between React's virtual representation of the DOM and the actual DOM.
Try not to think about React data bindings in terms of Angular bindings, rather think about it in terms of emulating what Angular bindings do within the context of step-by-step state changes.
Struggling to find or come up with an elegant answer to this one:
If I have multiple dynamic react components that are listening to one flux store to update their child components is it possible to emit changes to specific components rather than emitting changes to all the components that are registered to listen to changes on that store?
E.G: A dynamic component has a button and when clicked its tells the flux store to send some data to API. The dynamic component will it update its child view depending on the response and change emitted by the flux store. But since all the dynamic components are listening to the store they will all update their child views which is the undesired behaviour. Ideally the flux store could identify which component to emit the change to, or the components can identify that change is not for them.
Is this possible? Or does it go against flux principles?
I don't know if it violate flux architecture, but it seems not leveraging some beauties of it.
The beauty of a simple emit change (without change detail) is that a store wouldn't need to have explicit knowledge on views, also, with the React Virtual Dom framework, it shouldn't cost too much performance hit.
To further optimize the performance, you can implement shouldComponentUpdate on your React view (base on the differences in it's own properties), to avoid triggering the tree-diff algorithm.
See this: https://facebook.github.io/react/docs/component-specs.html
== Add more info ==
In more traditional MVC, the model will emit changes to a particular source and with particular details, e.g.
this.emit({
details: { x: 'x', y: 'y' },
source: objectA
)};
The view (or controller) that receive this needs such detail to update it's Dom, you will call the update(changes.details) instead of the initial render() method because Dom manipulation is expensive.
ReactJS 'solved' this by having another virtual Dom layer, which use pure Javascript to compute the 'optimal' differences in Dom manipulation, so in React, you never have a method call update(), you will always call render() base on current state of the view, and React does the optimization for you.
So using Flux with React, your store can just emit change without any details and the views that listen to it can just render with 'optimal' Dom manipulation (so if it's state hasn't been changed, there will be no Dom manipulation).
But of course, you will say in this case React will still trigger the virtual Dom diff computation, which still cost something. So to further optimize it, you can implement shouldComponentUpdate on a view that contains big sub-tree (base on it's own state), to avoid React to run the diff computation.
The beauty of emit a simple change, besides easier code, is that Store can be pretty much decoupled from view.
For example if you trigger specific change details for particular views, then you will need to remove or change code in store(s) when the view is not listening the that store anymore.
It does not go against flux principle but beware not having only one big store, sometime it's better to split in several tiny store.
But I think I understand your use case, one store containing a collection of similar objects (like a backbone collection).
So lets say your store receive a new object or an array of new object (or things to update in your store), you have a register function which will add this object (or update) to your store.
For sure this object has an id field (or something similar). Then for each new object of your array you just received you'll emit the id.
And your view are binded to their id as change event. Basically you use your store like an array, when the array is change you emit the key as event. Your view listen to this key/id and then get the specific data from your store still using this id/key.
Hope it's clear, let me know.