If there is a view that displays elements in an array, and the array grows; how does angular refresh the DOM? Does it just append the new elements to the existing view or recreates the whole thing?
I fear that I might run into a Schlemiel the Painter's algorithm if I keep adding stuff to lists...
The api appends a new element to the end of the dom tree (well at least the section you are working with) or beginning depending on the filter mechanic you implement. You should be safe, adding as many elements you like of course there is a limit to how big you can get in reality. However for sane amounts of items you should be perfectly fine.
Related
That's obvious that for the diffing algorithm in React keys are essential. But I was wandering, why React just can't automatically generate keys based on the content we iterate over?
I also assume that items can share some similarity, or cab be identical in terms of content, but isn't it possible to generate keys once user open a page and somehow attach them to the items, so it is stable?
Or maybe there where attempts to solve the problem, if so, I would be grateful if you share it to me.
Update
Thank you guys for your answers, I've learnt a lot!
Also a thing I had in mind: what we developers do when there is no stable id (e.g. user added an item which is not yet saved into DB). In the cases we just generate id, and attach it to the object, or element in an array, but we do not generate ids on a fly, so it remains stable over time.
What if React just generate ids for all arrays which are involved into rendering process, in other words, arrays which are directly used in render function?
It can be done only once, during phase Commit phase, or whatever. Also I believe, the id can be readonly, or something, so user can't erase the id.
p.s.s
While I was writing p.s. question above, I realized, autogenerating id for arrays wouldn't work, since I've missed two things. All side effect react can do only during the Commit phase, but not Render phase. But that's not the main problem.
The main problem is when we use filtering or sorting on a back-end side. Since we receive a new array, filtered one, we would need to regenerate ids for those elements, but basically, that's the same html elements, in which we can change content to match filtering order. That's the same as Slava Knyazev mentioned.
React can't generate keys, because the entire point of keys is for you to help React track elements during it's tree-diffing stage.
For example, lets say you have the following code, where you naively use content instead of identifiers for your keys:
const people = usePeople(); // [{ id: "1", name: "James"}, {id: "2", name: "William"}]
return <ul>{people.map(p => <li key={p.name}>{p.name}</li>}</ul>
The above code will function and behave as you would expect. But what happens if the name of a person changes? To understand it, lets look at the tree it generates:
ul
li(James) James
li(William) William
If James becomes Josh between renders, the new tree will look like this:
ul
li(Josh) Josh
li(William) William
React will compare the two results and conclude the following:
li(James) is to be removed
li(Josh) is to be added
However, if we set our key prop to p.id, then the old and new tree will look as follows, respectively:
ul
li(1) James
li(2) William
ul
li(1) Josh
li(2) William
And when React compares the two, it will identify that James has become Josh, and needs only the text adjusted.
In the first scenario, the <li> component is completely destroyed, and a completely new component takes its place. Both of these actions run a complete React lifecycle for the component. In the second, it remains untouched, and only the text inside changes.
While in this contrived scenario, the performance penalty in the first case in minimal, it may be very significant with complex components.
I believe, unless your data is 100% certainly going to sort in one way and never change, key={index} isn't a good key (which is what I assume you want your auto-generated keys to be). You'd ideally want something that is unique to each item, regardless of the order.
It's explained in more detail in the new beta react docs https://beta.reactjs.org/learn/rendering-lists#where-to-get-your-key
I think what you are implying is React could potentially choose to use something like a stable hash (say sha1 on a serialised string or something) on the object to generate a unique key. I think this actually would work in many cases, and even gave me pause for thought for a while! Your question is actually a really good one, and a deep one.
However, it wouldn't work in every case. I think it would work only on a static object which has no methods or anything attached. On a JS object, not all properties are enumerable. Hashing something could only ever happen on the enumerable objects of properties, but the dev may have non-enumerable yet-still-unique methods attached to these objects. In fact, even enumerable methods cant really be serialised reliably and they could be what makes the object unique. Not to mention the complexities of reliably hashing something with prototypical inheritance involved.
I suspect there's also a performance aspect to this. Hashing is cheap, but no that cheap. Most cases can be keyed by just referencing a unique ID in the object, which is vastly cheaper. When enumerating a very large number of objects, these things matter, and so its better to defer to the developer. After all, if you really do want to hash it, its just one function call in userland -- and this saves great confusion on developer side when it doesn't work. The Principle of least astonishment comes to mind.
There's also an aspect of how this would limit the power of how expressive JSX can be due to it basically allowing free-form JS. You would probably have to supply some low level <React.Map> component primitives in order for react to supply this default key handling which implies you are a bit more restrained on what you can and can't do (complex functional chains).
I read through all the articles in internet. Still i cant understand and mind is puzzling me questions again and again that is
At the end of all the virtual DOM it is going to call the browser API to update the real DOM then how come it will be faster?
Is virtual DOM of React have special access to browsers core API's to modify?
I cant understand? Any resolves this questions Thanks in advance
Here is a talk given circa 2013 (v0.4.0) by the two guys behind React. They describe exactly how it works. Unlike data binding and dirty checking (Angular, etc.) React uses one render method that's called recursively. It then generates a long string that is a representation of the DOM. The concept is actually really simple.
https://www.youtube.com/watch?v=XxVg_s8xAms
Yes, you are right finally the task is to update real dom but the virtual dom comes in picture before updating the real dom. how ?
Suppose you want to update any/many element(s) in Dom tree element then there should be a mechanism to find which element(s) needs to be updated in real dom i.e the browser screen we see.
So this dom finding algorithm executed in virtual dom i.e a javascript copy of real dom(a html dom tree).
React creates two virtual dom, one from existing real dom and other from the changes made. These two virtual dom comparison saves time. The difference of this comparison used for updating real dom.
At the end of all the virtual DOM it is going to call the browser API to update the real DOM then how come it will be faster?
Any speed benefits come from minimizing the number of DOM manipulations that are needed and doing them all at once. The virtual DOM is react's way of calculating the minimum set of changes.
Here's what i mean by calculating the minimum set of changes: The page starts off looking one way, and then you want to make it look some other way. To get there, you're going to need to make one or more changes to the DOM, but there are many different ways you could do it.
A really bad way to update the page would be to wipe the entire document, and then rebuild every single element from scratch. Most likely though, you can reuse most of the page and just make a few updates to select parts of the page: add a div here; update a property there, add an event listener there. That's what you want: a small number of steps that take the old page and turn it into the new page.
While going through react I came up with the following doubts:
DOM operations are very expensive
But eventually react also does the DOM manipulation. We cannot generate a view with Virtual DOM.
Collapsing the entire DOM and building it affects the user experience.
I never did that, Mostly what I do is changing the required child node(Instead of collapsing entire parent) or appending HTML code generated by JS.
Examples:
As a user scrolls down we append posts to parent element, even react
also have to do it in same way. No one collapse entire dom for that.
When a user comment on a post we append a div(comment element(HTML code)) to that particular post comment list. I think no one collapse entire post(dom) for that
3) "diffing" algorithm to check changes:
Why we need a algorithm to check changes.
Example:
If I have a 100 posts, whenever a user clicks on edit button of a particular post, i do it as follows
$(".postEdit").click(function(){
var post_id = $(this).data("postid");
//do some Ajax and DOM manipulation to that particular post.
})
I am telling the DOM to change particular element, then how does diffing help?
Am I thinking in a wrong way? If so, please then correct me.
You are correct that people don't tend to collapse and recreate the entire DOM when they need to update a single element. Instead, the best practice is to just rebuild the element you need. But what if a user takes an action that actually impacts lots of elements? Like it they star a post or something, you want to reflect that on the post and maybe in a stars count elsewhere on the page. As applications get complex enough changing all of the parts of a page that need to be changed becomes really complicated and error prone. Another developer might not be aware that there is a "stars count" elsewhere on the page and would forget to update it.
What if you could just rebuild the entire DOM? If you wrote your render methods and stored your state such that at any point, you could with certainty render the entire page from scratch? That removes a lot of these pain points, but obviously you lose all the performance gains you got from manually altering parts of the DOM by hand.
React and the virtual dom give you the best of both worlds. You get that optimized DOM updating, but as a developer you don't have to keep a mental model of the entire application and remember what you need to change for any given user or network input. The virtual dom will also potentially implement these changes more effectively than you by literally only rebuilding the elements you need. At some point you might be rebuilding more than you should "just in case".
Hope this sort of makes sense!
This discussion can be very helpful to understand Virtual DOM and it's implementation in different UI frameworks.
Why is React's concept of Virtual DOM said to be more performant than dirty model checking?
There are couple of other links as well which explains it in better way.
https://auth0.com/blog/face-off-virtual-dom-vs-incremental-dom-vs-glimmer/
http://teropa.info/blog/2015/03/02/change-and-its-detection-in-javascript-frameworks.html
I am new to angular, so maybe I'm going about this completely wrong. I am attempting to make a treeView with angularJS directives. The code that I have so far accomplishes this, except that there appears to be a memory leak as each time the tree view reloads it slows down, and eventually crashes the browser.
I have created the following two directives to accomplish my task jscTreeView and jscTreeNode
This fiddler has my source, it builds you a random tree, and gives you the ability to choose the amount of nodes in the tree. If you bump that number up to a higher number, and reload several times you will notice that it progressively slows down to each time.
Any ideas on how to clean up after myself would be greatly appreciated, thanks.
Edit:
This fiddler is a second attempt with this one I went in a completely different direction. It is much more efficient, and the code is more clean in my opinion. However, this one has an issue too. periodically, and seemingly randomly on refresh of the tree this one throws an infinite digest exception.
Note: not all of the functionality that was in the former tree is in the current tree yet. That is just because I have not programmed it yet.
As the discussion in the comments indicates, I was creating, but never properly releasing, scopes in my tree view. While the solution was not very easy to figure out it is actually quite an easy solution, and clarified things a lot for me.
What I needed to do was make a clone of the root scope of my tree var newScope = scope.$new();, I then built all of the rest of the subtrees as well as their associated nodes and compiled with the cloned scope newScope. After the compile it stores the cloned scope into a variable private to the directive lastScope = newScope;. When the watch property is updated, and calls back to my directive the last cloned scope is destroyed lastScope.$destroy();. Destroying that cloned scope automatically destroys any child scope created beneath it (the nodes, as well as the subtrees). A new clone of the scope is created, and the process is repeated, thanks to #Jorg's tool to count scopes, I can see that everything is being cleaned up nicely on each iteration. Here is a fiddle to the solution.
I am writing new directive that is going to use ng-repeat to create nested child's and more. What I have seen so far is there are all kind of problems using this great tool of angular. You get a great binding to data, but when data increases, you are going to suffer from very low performance and defects hard to be solve. This is making the all directive very hard to maintain and reuse.
So I wanted to ask all of you who have a lot of experience with AngularJS, what are the best things to be aware of in order to use it properly and not doing huge mistakes.
Did you ever think not using it and just make your own loop?
Be glad to hear your points.
Let’s quickly recap how we can use ng-repeats (along with optional filters):
<div ng-repeat="stock in ctrl.stocks | filter:someCondition">
</div>
We can also use ng-repeats to iterate over objects (In case you hadn’t known this):
<div ng-repeat="(key, stock) in ctrl.stocksMap | filter:someOtherCondition">
</div>
where stocksMap is an object map, where the key is the id of the stock, and the value is the individual stock object. One common misunderstanding now is how AngularJS creates and displays the UI, based on this ng-repeat. This is how AngularJS works under the covers (in a nutshell) when you use ng-repeat:
It iterates over each item in the array (or each key, value in the
object)
It runs each item via any filters that are present in our
expression, to check if it should be displayed or not
It calculates a hash value by which it identifies the object (which
is by reference by default)
It checks if it has already created a DOM element for the hash value
previously If so, it reuses it
If not, it creates a DOM element based on the ng-repeat template
All the DOM manipulations are taken and inserted in an optimal
manner into the actual DOM
A watch is added on the array, which triggers step 1 again if the
array undergoes any change
For More information you can refer this LINK