This is the situation:
This component renders many data as a list. If I use React state/props to control the DOM style(add classes or modify some attributes), React will always run the render() function when user reacts with the list, like mouseover, click and etc..
Though React has virtual DOM technology, but I think it is still very inefficient to run render() every time. The documents do not recommend to manipulate DOM directly, but I think it is more efficient. What should I do? Thx.
I wouldn't mix writing React with directly manipulating the DOM; do either but not both.
If you are already using React, just use it for what you want. If possible, break the components into as small of pieces as possible; this will help the number renders.
It may be slightly more inefficient to have React re-render too much, but remember that React has been heavily optimized for DOM manipulation.
As far as rerendering in react is concerned, it has been heavily optimised. You may think that the render() function runs on every small manipulation but the thing that is not visibile is that the rerender doesn't occur for the entire DOM rather on only the portion that has changed.
React uses the virtual DOM technology and then it takes out the difference between the current and the virtual dom much like string comparison and then only renders the difference and is thus highly efficient.
So I would recommend you to follow the documentation and not mix DOM manipulation with react.
Related
Specifically used just to view the heights/widths (getBoundingClientRect) of elements. I recently encountered a need to find all the separate heights of a dynamic amount of child elements to perform a calculation. I added a ref within the child component, and passed a function down from the parent in an attempt to update the parent's list of child dimensions (which was in state). I found this to be overtly complex and confusing and unreliable. So, in the parent, I just did a simple for loop with getElementById after giving each child an id of child-${index}.
I know you are NOT supposed to do any direct DOM manipulation in React; however, if your goal is read some data only, then is it an issue or bad practice?
It might not be a problem right now, but I would consider using getElementById instead of a ref bad practice in general (or at least call it "a workaround").
1
getElementById works "outside" of React, so you are not using React here.
That might work for now, but also might interfere with what might do React at some time.
E.g. you might access or hold a reference to a DOM node, and React might decide to remove that node while you were reading it. I don't see why this might happen in your
example, but when using two separate systems it is hard to keep track of the possible consequences.
2
With the id child-${index} you have introduced a logical dependency (coupling) between the parent and the child.
The id child-${index} acts as a reference here, and has to be kept in sync manually.
This might be easier in a short term, but is actually more complex as a general approach (e.g. less maintainable, reusable, ...).
You could say, Reacts whole purpose is to avoid such complexities.
Your components should be as independent of each other as possible, and should only communicate through the props.
suggestion
I suggest to avoid both getElementById and passing a ref, and have the children know their size (e.g. using a custom hook),
and pass only the sizes up to the parent (not the ref).
If that is not possible, I would prefer to use refs.
Also note that "confusion" is not the same as "complexity": Confusion can be decreased by acquiring more information, but complexity is an
inherent property of a system.
I want to prevent re-rendering of the whole tree, so, I thought to use the setNativeProps to update the specific component when needed, but setNativeProps is not working for all components. I am using both setState and setNativeProps in my react native application. The setState works just fine for all components but setNativeProps do not works for all components.
What is the difference between setState & setNativeProps? For what kind of components setNativeProps should and shouldn't be used? A little example will be more appreciated. Thanks !!!
The React-Native Documentation explains this very well :
It is sometimes necessary to make changes directly to a component without using state/props to trigger a re-render of the entire subtree. When using React in the browser for example, you sometimes need to directly modify a DOM node, and the same is true for views in mobile apps. setNativeProps is the React Native equivalent to setting properties directly on a DOM node.
check this link for reference
Use setNativeProps when frequent re-rendering creates a performance bottleneck
so basically the only use case i can see for it, is when you are creating continuous animations and you don't want to affect the performance of your app.
in almost all other cases, setState will be more than enough.
And in case you need to control when your component should re-render check out
shouldComponentUpdate
I am hearing the term "mount" too many times while learning ReactJS. And there seem to be lifecycle methods and errors regarding this term. What exactly does React mean by mounting?
Examples: componentDidMount() and componentWillMount()
The main job of React is to figure out how to modify the DOM to match what the components want to be rendered on the screen.
React does so by "mounting" (adding nodes to the DOM), "unmounting" (removing them from the DOM), and "updating" (making changes to nodes already in the DOM).
How a React node is represented as a DOM node and where and when it appears in the DOM tree is managed by the top-level API. To get a better idea about what's going on, look at the most simple example possible:
// JSX version: let foo = <FooComponent />;
let foo = React.createElement(FooComponent);
So what is foo and what can you do with it? foo, at the moment, is a plain JavaScript object that looks roughly like this (simplified):
{
type: FooComponent,
props: {}
}
It's currently not anywhere on the page, i.e. it is not a DOM element, doesn't exist anywhere in the DOM tree and, aside from being React element node, has no other meaningful representation in the document. It just tells React what needs to be on the screen if this React element gets rendered. It is not "mounted" yet.
You can tell React to "mount" it into a DOM container by calling:
ReactDOM.render(foo, domContainer);
This tells React it's time to show foo on the page. React will create an instance of the FooComponent class and call its render method. Let's say it renders a <div />, in that case React will create a div DOM node for it, and insert it into the DOM container.
This process of creating instances and DOM nodes corresponding to React components, and inserting them into the DOM, is called mounting.
Note that normally you'd only call ReactDOM.render() to mount the root component(s). You don't need to manually "mount" the child components. Every time a parent component calls setState(), and its render method says a particular child should be rendered for the first time, React will automatically "mount" this child into its parent.
React is an isomorphic/universal framework. That means that there is a virtual representation of the UI component tree, and that is separate from the actual rendering that it outputs in the browser. From the documentation:
React is so fast because it never talks to the DOM directly. React maintains a fast in-memory representation of the DOM.
However, that in-memory representation is not tied directly to the DOM in the browser (even though it is called Virtual DOM, which is an unfortunate and confusing name for an universal apps framework), and it is just a DOM-like data-structure that represents all the UI components hierarchy and additional meta-data. Virtual DOM is just an implementation detail.
"We think the true foundations of React are simply ideas of components and elements: being able to describe what you want to render in a declarative way. These are the pieces shared by all of these different packages. The parts of React specific to certain rendering targets aren't usually what we think of when we think of React." - React js Blog
So, the conclusion is that React is Rendering agnostic, which means that it doesn't care about what is the final output. It can be a DOM Tree in the browser, it can be XML, Native components or JSON.
"As we look at packages like react-native, react-art, react-canvas, and react-three, it's become clear that the beauty and essence of React has nothing to do with browsers or the DOM." - React js Blog
Now, that you know how React works, it is easy to answer your question :)
Mounting is the process of outputting the virtual representation of a component into the final UI representation (e.g. DOM or Native Components).
In a browser that would mean outputting a React Element into an actual DOM element (e.g. an HTML div or li element) in the DOM tree. In a native application that would mean outputting a React element into a native component. You can also write your own renderer and output React components into JSON or XML or even XAML if you have the courage.
So, mounting/unmounting handlers are critical to a React application, because you can only be sure a component is output/rendered when it is mounted. However, the componentDidMount handler is invoked only when rendering to an actual UI representation (DOM or Native Components) but not if you are rendering to an HTML string on the server using renderToString, which makes sense, since the component is not actually mounted until it reaches the browser and executes in it.
And, yes, Mounting is also an unfortunate/confusing name, if you ask me. IMHO componentDidRender and componentWillRender would be much better names.
Mounting refers to the component in React (created DOM nodes) being attached to some part of the document. That's it!
Ignoring React you can think of these two native functions as mounting:
replaceChild
appendChild
Which are likely the most common functions React uses to mount internally.
Think of:
componentWillMount === before-mount
And:
componentDidMount === after-mount
https://facebook.github.io/react/docs/tutorial.html
Here, componentDidMount is a method called automatically by React when a component is rendered.
The concept is that you're telling ReactJS, "please take this thing, this comment box or spinning image or whatever it is I want on the browser page, and go ahead and actually put it on the browser page. When that's done, call my function that I've bound to componentDidMount so I can proceed."
componentWillMount is the opposite. It will fire immediately BEFORE your component renders.
See also here
https://facebook.github.io/react/docs/component-specs.html
Finally, the "mount" term seems to be unique to react.js. I don't think it is a general javascript concept, or even a general browser concept.
Mounting refers to the initial page loading when your React component is first rendered. From React documentation for Mounting: componentDidMount:
Invoked once, only on the client (not on the server), immediately after the initial rendering occurs. At this point in the lifecycle, the component has a DOM representation which you can access via React.findDOMNode(this).
You can contrast this with componentDidUpdate function, which is called everytime that React renders (except for the initial mount).
The main goal of React js is to create reusable components. Here, components are the individual parts of a webpage. For example, in a webpage the header is a component, the footer is a component, a toast notification is a component and etc. The term "mount" tells us that these components are loaded or rendered in the DOM. These are many top-level APIs and methods dealing with this.
To make it simple, mounted means the component has been loaded to the DOM and unmounted means the components has been removed from the DOM.
When writing tests for React components, you have to render them into the DOM in order to make assertions about their correctness. For example, if you want to test that a certain class is added to a node given a certain state, you have to render into a DOM node, then inspect that DOM node via the normal DOM API.
The thing is, considering React maintains a virtual DOM into which it renders, why can't we just assert on the virtual DOM once the component is rendered? That seems to me like a very good reason to have something like the virtual DOM.
Have I missed something?
You haven't really missed anything. We're working on making this better. The virtual parts have always been very much an implementation detail of React, not exposed in any useful or reliable way for testing. We have some methods in our test helpers which wrap up the internal lookups which sometimes avoids looking at the actual DOM but we need more.
I saw a React dev talk at (Pete Hunt: React: Rethinking best practices -- JSConf EU 2013) and the speaker mentioned that dirty-checking of the model can be slow. But isn't calculating the diff between virtual DOMs actually even less performant since the virtual DOM, in most of the cases, should be bigger than model?
I really like the potential power of the Virtual DOM (especially server-side rendering) but I would like to know all the pros and cons.
I'm the primary author of a virtual-dom module, so I might be able to answer your questions. There are in fact 2 problems that need to be solved here
When do I re-render? Answer: When I observe that the data is dirty.
How do I re-render efficiently? Answer: Using a virtual DOM to generate a real DOM patch
In React, each of your components have a state. This state is like an observable you might find in knockout or other MVVM style libraries. Essentially, React knows when to re-render the scene because it is able to observe when this data changes. Dirty checking is slower than observables because you must poll the data at a regular interval and check all of the values in the data structure recursively. By comparison, setting a value on the state will signal to a listener that some state has changed, so React can simply listen for change events on the state and queue up re-rendering.
The virtual DOM is used for efficient re-rendering of the DOM. This isn't really related to dirty checking your data. You could re-render using a virtual DOM with or without dirty checking. You're right in that there is some overhead in computing the diff between two virtual trees, but the virtual DOM diff is about understanding what needs updating in the DOM and not whether or not your data has changed. In fact, the diff algorithm is a dirty checker itself but it is used to see if the DOM is dirty instead.
We aim to re-render the virtual tree only when the state changes. So using an observable to check if the state has changed is an efficient way to prevent unnecessary re-renders, which would cause lots of unnecessary tree diffs. If nothing has changed, we do nothing.
A virtual DOM is nice because it lets us write our code as if we were re-rendering the entire scene. Behind the scenes we want to compute a patch operation that updates the DOM to look how we expect. So while the virtual DOM diff/patch algorithm is probably not the optimal solution, it gives us a very nice way to express our applications. We just declare exactly what we want and React/virtual-dom will work out how to make your scene look like this. We don't have to do manual DOM manipulation or get confused about previous DOM state. We don't have to re-render the entire scene either, which could be much less efficient than patching it.
I recently read a detailed article about React's diff algorithm here: http://calendar.perfplanet.com/2013/diff/. From what I understand, what makes React fast is:
Batched DOM read/write operations.
Efficient update of sub-tree only.
Compared to dirty-check, the key differences IMO are:
Model dirty-checking: React component is explicitly set as dirty whenever setState is called, so there's no comparison (of the data) needed here. For dirty-checking, the comparison (of the models) always happen each digest loop.
DOM updating: DOM operations are very expensive because modifying the DOM will also apply and calculate CSS styles, layouts. The saved time from unnecessary DOM modification can be longer than the time spent diffing the virtual DOM.
The second point is even more important for non-trivial models such as one with huge amount of fields or large list. One field change of complex model will result in only the operations needed for DOM elements involving that field, instead of the whole view/template.
I really like the potential power of the Virtual DOM (especially
server-side rendering) but I would like to know all the pros and cons.
-- OP
React is not the only DOM manipulation library. I encourage you to understand the alternatives by reading this article from Auth0 that includes detailed explanation and benchmarks. I'll highlight here their pros and cons, as you asked:
React.js' Virtual DOM
PROS
Fast and efficient "diffing" algorithm
Multiple frontends (JSX, hyperscript)
Lightweight enough to run on mobile devices
Lots of traction and mindshare
Can be used without React (i.e. as an independent engine)
CONS
Full in-memory copy of the DOM (higher memory use)
No differentiation between static and dynamic elements
Ember.js' Glimmer
PROS
Fast and efficient diffing algorithm
Differentiation between static and dynamic elements
100% compatible with Ember's API (you get the benefits without major updates to your existing code)
Lightweight in-memory representation of the DOM
CONS
Meant to be used only in Ember
Only one frontend available
Incremental DOM
PROS
Reduced memory usage
Simple API
Easily integrates with many frontends and frameworks (meant as a template engine backend from the beginning)
CONS
Not as fast as other libraries (this is arguable, see the benchmarks below)
Less mindshare and community use
Here's a comment by React team member Sebastian Markbåge which sheds some light:
React does the diffing on the output (which is a known serializable format, DOM attributes). This means that the source data can be of any format. It can be immutable data structures and state inside of closures.
The Angular model doesn't preserve referential transparency and therefore is inherently mutable. You mutate the existing model to track changes. What if your data source is immutable data or a new data structure every time (such as a JSON response)?
Dirty checking and Object.observe does not work on closure scope state.
These two things are very limiting to functional patterns obviously.
Additionally, when your model complexity grows, it becomes increasingly expensive to do dirty tracking. However, if you only do diffing on the visual tree, like React, then it doesn't grow as much since the amount of data you're able to show on the screen at any given point is limited by UIs. Pete's link above covers more of the perf benefits.
https://news.ycombinator.com/item?id=6937668
In React, each of your components have a state. This state is like an observable you might find in knockout or other MVVM style libraries. Essentially, React knows when to re-render the scene because it is able to observe when this data changes. Dirty checking is slower than observables because you must poll the data at a regular interval and check all of the values in the data structure recursively. By comparison, setting a value on the state will signal to a listener that some state has changed, so React can simply listen for change events on the state and queue up re-rendering.The virtual DOM is used for efficient re-rendering of the DOM. This isn't really related to dirty checking your data. You could re-render using a virtual DOM with or without dirty checking. You're right in that there is some overhead in computing the diff between two virtual trees, but the virtual DOM diff is about understanding what needs updating in the DOM and not whether or not your data has changed. In fact, the diff algorithm is a dirty checker itself but it is used to see if the DOM is dirty instead.
We aim to re-render the virtual tree only when the state changes. So using an observable to check if the state has changed is an efficient way to prevent unnecessary re-renders, which would cause lots of unnecessary tree diffs. If nothing has changed, we do nothing.
Virtual Dom is not invented by react. It is part of HTML dom.
It is lightweight and detached from the browser-specific implementation details.
We can think virtual DOM as React’s local and simplified copy of the HTML DOM. It allows React to do its computations within this abstract world and skip the “real” DOM operations, often slow and browser-specific. Actually there is no big differenc between DOM and VIRTUAL DOM.
Below are the points why Virtual Dom is used (source Virtual DOM in ReactJS):
When you do:
document.getElementById('elementId').innerHTML = "New Value" Following thing happens:
Browser needs to parse the HTML
It removes the child element of elementId
Updates the DOM value with new value
Re-calculate the css for the parent and child
Update the layout i.e. each elements exact co-ordinates on the screen
Traverse the render tree and paint it on the browser display
Recalculating the CSS and changed layouts uses complex algorithm and
they effect the performance.
As well as updating the DOM properties ie. values. It follows a algorithm.
Now, suppose if you update DOM 10 times directly, then all the above steps will run one by one and updating DOM algorithms will take time to updates DOM values.
This, is why Real DOM is slower than virtual DOM.