React - append-only behavior with createPortal or appendChild? - javascript

I have a large number of elements being rendered by a common parent. When the user takes an action, a few of the elements should be removed, and a few additional elements should be appended. Doing this the 'React way,' the parent has an array that owns the state of all the children elements. On user on click, the parent immutably modifies the array and voila...new elements in the DOM. The problem is that it's often sluggish due to having to compare every element on the page, even with element keys and memoization. I have been fighting with React's diffing algorithm to make this work efficiently. Ideally, this parent component would be responsible solely for appending new children...once they're bootstrapped, they would control their own state.
I've just read about Portals, and am trying to understand whether ReactDOM. createPortal(<Child />, document.getElementById('myFavoriteDiv')) will allow this append-only behavior without altering any of the previously-rendered children. The non-declarative way of doing this I think would be appendChild, but I think that's frowned upon. If this doesn't work like that, what alternatives would you suggest?

Related

MutationObserver and DOM timings

I am using said MutationObserver to watch for changes on an HTMLElement.
I dynamically add children to a div and the observer does a nice job at executing the provided callback anytime changes are detected in the div's tree.
I am adding the children all together (by mounting a React component) and there is an action that I need to perform only when I know that all of them are added; if I perform that action also before all the children are added to the DOM, then I would irreparably mess everything up.
The observer possibly would run the callback a bunch of times within a fraction of a second just because I added a bunch of children, so a possible solution would be to set a timeout for this particular action.
Now since the action is vital for the interactivity of the page I need to wait as little as possible.
My question is: is there an order of magnitude for the time needed to add a handful of children to an element? Something like 1ms, 100ms or 1 second? How long is it safe to wait?
But also: are you aware of any other possible solution to the problem?
PS: my question is a generalisation of this question, which has been solved by checking for the appearance of a particular entity (a background-image), but I am working with a reusable custom hook and waiting for the appearance of an element that could be an input as it could be a button and by the way it would not be the only one of its type among the children being added to the div, nor it is granted that it will be present on the DOM once all the children are added. I just need to check for its presence once all the children are added and that's it. A different approach is needed.

Does React (hooks) require the use of states in order to do its virtual dom diff magic?

This always puzzled me. If I said "Thank you React, your state hooks are awesome, but I'm just gonna do my direct dom manipulation here", would react still do the virtual dom comparison in order to update only that specific item? would I still benefit from the virtual dom 'situation'?
Is there any difference between using react to directly manipulate dom without states, and using a standard HTML file with imported vanilla js code?
For clarity, here's an example,
Let's say I have function printHellol() triggered by a button 'click' in my JSX. The function targets the ID of an element and changes the text content.
I couldn't find the answer anywhere. Thanks!
Anything that his held in state becomes part of an object that react renders as a detached element from the dom. It's in essence creating a separate environment for all states. Anything that is used outside of state can be considered to be part of the direct dom object, causing the page to be rerendered when updates occur. In other words you would need to use the react specific state if you want to access the virtual dom specific environment.

React: Is a component entirely re-rendered on every setState()?

Just got a bit confused about the lifecycle in react.
Here's my understanding...
The render() always run first, right? If so...
It implies that a setState() inside useEffect() only runs after the initial render(), correct?
Question:
When the above happens, does the entire component re-render?So that would be a second time the component renders just to load a state.
Wouldn't that be a performance issue?
On every state change render is called again but not whole component renders again.
React keeps Two DOM Tree Objects in memory:
Virtual DOM
Real DOM
React have a very intelligent and powerful diffing algorithm which calculates difference between previous DOM state and Next DOM state called Reconciliation process.
Only those sub elements which have changed would be re-rendered.Keys help React identify which items have changed, are added, or are removed.Keys should added to list or array elements , to give those elements a stable identity
For example, you want to delete <input key="i42"/> element from your list so on left side Its Actual DOM Tree Object and on Right side its Virtual DOM tree object. React calculates difference between two and only the difference will be Recreated Intelligently.
https://reactjs.org/docs/lists-and-keys.html
https://reactjs.org/docs/reconciliation.html#the-diffing-algorithm
So the thing about React is that there are two DOMs -- one is the actual DOM, and the other is the virtual DOM. Every time there is a state change, the virtual DOM re-renders. React then compares the changes to the virtual DOM vs changes to the real DOM, and only updates the real DOM with what has actually changed.
Re-rendering the virtual DOM is not a performance issue as it's super quick.
There's a cool article you can read about this

Algorithm to update only the changed innerHTML of the document

I have 2 JS variables. before and after. They contains the SAME html document, but have some modification. About 1%-10% change between them. I want to update the body from before to after. The variablesbefore and after are raw string.
I can do something like that:
document.documentElement.innerHTML=after
The problem is that if I render this way it not look good. The render takes time, and there is a white screen between the renders. I want to show the user 10 modification in a second (video of modifications)
So what I want to do. I want to search and find only the elements that changed only by analyze the HTML text of before and after.
My way of solution:
I can find the changes and the position in the text using Javascript Library for diff & match & patch.
The question is:
After I find the text changes. How to find only the elements who changed. I update only those elements.
I thought, maybe to create a range, that contains every change, and update the range, but how exactly to do that?
If anything unclear, please comment, I will explain better.
I found a very good library for it: https://github.com/patrick-steele-idem/morphdom
Lightweight module for morphing an existing DOM node tree to match a
target DOM node tree. It's fast and works with the real DOM—no virtual
DOM here!
Very easy to use, and doing exactly what I need
If I have understood your question correctly, then what I would have done is,
1) Make a new object (view Object) which will control the rendering of DOM elements. (Similar to MVC)
2) In this object, I would have created 3 functions.
a) init function (contains the event-handlers)
b) render1 function (which will contain elements in before element)
c) render2 function (which will contain elements in after element)
Whenever there is an event where I need to change the HTML of a class/id/body/document, I will change that in init function and call render2 function which contains the after element.
This should not give any error, however the browser has to work to render all the page, but rendering can be divided over multiple elements of document. So, whenever you need to render a part of document, make separate render functions.
p.s. there can be different approaches.
You must implement the LCS(Longest Common Subsequence). To understand better of this algorithm you can watch this youtube video. Also It's easier to first study Longest Common Substring.
I think I have a solution. virtual-dom can do the work for me. I can create two VTree, make a diff, and apply a patch.
From the documentation of virtual-dom:
virtual-dom is what I need.
Manual DOM manipulation is messy and keeping track of the previous DOM
state is hard. A solution to this problem is to write your code as if
you were recreating the entire DOM whenever state changes. Of course,
if you actually recreated the entire DOM every time your application
state changed, your app would be very slow and your input fields would
lose focus.
virtual-dom is a collection of modules designed to provide a
declarative way of representing the DOM for your app. So instead of
updating the DOM when your application state changes, you simply
create a virtual tree or VTree, which looks like the DOM state that
you want. virtual-dom will then figure out how to make the DOM look
like this efficiently without recreating all of the DOM nodes.
virtual-dom allows you to update a view whenever state changes by
creating a full VTree of the view and then patching the DOM
efficiently to look exactly as you described it. This results in
keeping manual DOM manipulation and previous state tracking out of
your application code, promoting clean and maintainable rendering
logic for web applications.
https://github.com/Matt-Esch/virtual-dom

Most efficient way of "pushing" data to Polymer elements

I have a situation in which I get data over a web socket, and performance is important. From the docs I understand that there are various ways of "pushing" the data I'm receiving to my Polymer elements, but I'm curious which one will be most efficient. So far I've created an element that can be included in a template, where the parent element will observe any changes in the data property and react accordingly. I've also been experimenting with using a Behavior to accomplish the same thing, though instead of needing to include a "data-element" in its template, it could just observe its own data property. I realize I could also use something like iron-signals to "push" the data via an event.
I'm not sure any of these methods are very efficient, since most of the time the changes to the "data" object will only apply to a small subset of all the observers. Another possible solution would be to "observe" a dynamic path, so like data.pathx instead of data.*, which would drastically reduce the number of times the observer callback gets fired, but I haven't come across anything that leads me to think that's possible, since each of my elements won't know if it should observe pathx or pathz until creation.
Like I said, performance is vital, and I feel there is way too much inefficiency if I have a small to medium sized dom-repeat of elements each observing a large data object of another element or individually holding a copy of that data on their own (like I assume a behavior would accomplish?).
I've looked at iron-meta, but I haven't been able to successfully data-bind to it, and from what I can tell from the docs, this data needs to be queried, whereas I need to be notified of changes.
Polymer doesn't really "observe" changes in elements. It just sets a setter for each property, and when it's called the UI is updated. So a dom-repeat template will not observe any change inside an object bound to it.
What could impact performance is unnecessary DOM manipulation, so if just a small subset of the data changes, re assigning all the array to the property is not ideal, and you should use notifyPath with just the sub property path and value that changed. Polymer will only update the DOM nodes affected.
If you have a way of knowing what sub properties changed in your data then you could obtain the object paths that have changed and call notifyPath for each of those and only a small number of DOM nodes will be changed.
Additional note:
If the number of elements in your array change, (added/removed) you should use the Polymer base array manipulation methods to update the property of your Polymer element, so it will change the DOM efficiently.

Categories