i have been reading many articles over this.
as per my understanding, virtual DOM is simple javascript object representation of real DOM.
whenever some state change happens, new Virtual DOm object is created and compared with old one using diff algorithm in o(n) time and updates the browser only the changed parts.
my question is , why didn't browsers do this themselves.?
also i tried checking differences between vanilla and react by using simple key press inside a text field using chrome devtools.
vanilla js and react have following traces under Main have following steps.
event: key press //both have
event: textInput //both have
recalcualte style// both have
Layout// only vanilla js has, React version doesn't have this step ??
update layer tree// both have
Paint.//both have
my question for above observation is why react version doesn't have layout step which is taking 0.48 ms in vanilla.
is this what causes react to be faster.
i also learned about layout thrashing and batch updates. as we don't interact with browser using DOM manipulation directly in React, batch update logic is undertaken by React. is this why react is efficient? so any new web developer needn't worry about effiecnt ways of updating browser(say like avoiding reflow/layout thrashing) instead focus on developing actual features and react does all for us?
it would be helpful if you can provide very basic demo example where virtual DOM has real advantage, i will use chrome devtools do the investigation myself. thanks :)
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
As you know, for the sake of good performance, we always try to minimize rendering in single page applications. For instance, in React whenever a state or props change inside a component, that change make that component re execute, re evaluate and finally re render.
So, are there any similar conditions in Angular ? and what are the best practices and patterns for reducing extra rendering ?
This is a huge topic to cover here but I would suggest the following article for starters: https://blog.angular-university.io/how-does-angular-2-change-detection-really-work/
TLDR;
What happens is that Angular at startup time will patch several low-level browser APIs, such as for example addEventListener, which is the browser function used to register all browser events, including click handlers. Angular will replace addEventListener with a new version
So by extending base functionality, angular understands changes that trigger re-evaluation of values and rerendering needs.
As an extra, we need to mention that the comparisons are not deep inside reference types, so some handling should happen.
In the article, several methods for performance tweaking are mentioned like
On push change detection method.
Disabling automatic detection for a component and triggering the cycles manually.
Using immutable objects with the help of libraries line immutable.js
As you can understand, these being their own pitfalls and considerations
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'm using jQuery along with ReactJS for several things. I've noticed that the out put of $(selector) is different when I do it within React vs directly in the browser console.
Due to this reason, certain javascript code that I execute directly in the browser console works, but it doesn't work when I write it within a React.
For example I have this table:
render(){
console.log(this.state.data);
return (
<Table striped bordered condensed hover id="files-table">
<thead>
<tr>
<th>stuff</th>
</tr>
</thead>
<tbody>
<tr>
<td>stuff</td>
</tr>
</tbody>
</Table>
);
}
On the one hand when I do console.log($('#files-table')) inside React let's say in the componentDidUpdate() hook, I see this output in the console:
... on the other hand the same console statement typed directly in the browser console shows this output (which is the one that I expect):
Can someone explain the differences?
I'm having a problem with implementing jQuery DataTables as putting $('#files-table').DataTable() in React componentDidUpdate() hook gives an error: $(...).DataTable is not a function Although it works in the browser (I know this error can be caused by loading jQuery twice, etc. but I don't think that's the case here).
This difference is caused by the fact that ReactJS uses a virtual DOM and when you're executing the jQuery selector in your browser console - your are accessing the actual (real) DOM.
Why Virtual DOM?
Rather than touching the real DOM directly, ReactJS is building an abstract version of it (a copy). The main problem that ReactJS is solving with this approach is that the DOM was never optimized for creating dynamic UI and writing to the browser's DOM is relatively slow.
Consider the Virtual DOM as a lightweight copy of the actual DOM. Like the actual DOM, the Virtual DOM is a node tree that lists elements and their attributes and content as objects and properties. React's render() method creates a node tree from React components and updates this tree in response to mutations in the data model, caused by actions.
One would think that re-rendering the entire Virtual DOM every time there’s a possibility that something has changed would be wasteful — not to mention the fact that at any one time, React is keeping two Virtual DOM trees in memory. But, the truth is that rendering the Virtual DOM will always be faster than rendering a UI in the actual browser DOM. It doesn’t matter what browser you’re using: this is just a fact.
React does this magic by attaching attributes to elements in your document and manipulating them individually (using these very specific ID attributes) after doing the diff to determine what needs updating. The Virtual DOM inserts additional steps into the process, but it creates an elegant way to do minimal updates to the browser window without you having to worry about the actual methods being used or even what needs to be updated and when.
More info about the differences between the Virtual and the actual DOM you can find explained in this article and in the ReactJS docs as well.
How to integrate jQuery DataTables in ReactJS?
In your case - the jQuery DataTabes library modifies the DOM. So, you need to keep React out of it's way. React works best when it has full control of the DOM. But in your case - you need to pass the control to jQuery.
You need to create a component to manage the jQuery DataTabes. This component will provide a React-centric view of the jQuery component. Moreover, it will:
Use React lifecycle methods to initialize and teardown the plugin;
Use React props as plugin configuration options and hook up to plugin's methods events;
Destroy the plugin when component unmounts.
Take a look at my answer here. It contains the full details and detailed explanation how to integrate a jQuery library in ReactJS. You can use the same approach.
I recently ported a heavy page to React. I've kept the html almost identical. The main difference being that, earlier, the server rendered html was directly given to the browser and now, the react rewrite pulls json via a server side API and uses React to manage the DOM.
I've seen heap snapshots for the earlier implementation going up to 55 MBs. For the same data, the heap snapshot for the React.js implementation comes to around 100+ MBs(almost double)
I understand that the json data held in memory will contribute to some increase in the memory consumed. But, when I examined the heap snapshot, I see that around 60% of the retained size is due to some objects whose retaining path contain deleteAllListeners > .... > unmountComponentAtNode . I am trying to understand what that means in terms of reducing the memory used.
Also, could the "data-reactid" attributes added by React to the DOM contribute to a non-negligible increase in memory consumption ?
This question has some more details that might help.
React is using something called Virtual DOM. Basically it constructs alternative DOM tree in memory, in addition to the existing browser DOM tree, but to perform efficient updates it has to keep last displayed Virtual DOM tree in memory, so it can generate fast and efficient updates to the browser DOM tree.
From details of second question, I understand that you have an infinite scroll, where you basically add new components (without removing new ones) when user scrolls down the page. So this should be the source of increased memory usage (since now you have data + virtual dom in memory, compared to the previous solution)
The way it fix it is to render only components which are actually visible to the user, you can try to use react-list, or implement your own component for this.