Is there a way to stop react from removing/changing nodes embedded in a react component.
For example, I have a react component that acts as a container for a non-react component that manages its DOM on its own. Is there a way to mark such components for reactjs, so that it does not modify its DOM?
In my case, I want my react component to be inline-editable by CKeditor, but react always removes/destroys the editor and all the nodes it has added to the DOM, because they were not defined in the react component itself and so it thinks that those elements should not be there.
Any ideas?
If you return false from a shouldComponentUpdate method on your component, then React will step out of the way and the entire reconciliation process will be skipped for that subtree. Of course, this means that you need to manage all DOM mutations yourself in that area and can't take advantage of React.
Take a look at dangerouslySetInnerHTML on https://facebook.github.io/react/tips/dangerously-set-inner-html.html.
This is the method for adding markup that doesn't sticks to React's update methods and also unsupported tags.
This way you can still update your component, while not updating parts of it.
Related
I am beginner in React JS. I came across React.memo() a HOC component that basically only re-renders the component if the component execution results are different from its previous result which it memonizes. But why do we need to use it if there is already a concept of Virtual DOM?
Like doesn't the Virtual DOM concept also do the same thing that is not re-rendering the component if the resultant virtual DOM is the same as the main DOM?
If I get it correctly aren't both follow same concept functionality wise?
React rendering happens at multiple levels. The virtual DOM kicks in at React<->Browser, but using React.memo() can reduce the amount of times that your React code needs to be run. In short:
Virtual DOM: Reduces HTML element creation/edits
React.memo(): Reduce React component re-renders (before even touching HTML)
For it's own - yes, similar to Virtual DOM. But from documentation:
[The memo()] component will usually not be re-rendered when its parent component is re-rendered. […] memoization is only a performance optimization. […] React normally re-renders a component whenever its parent re-renders.
So in other words you can use React.memo() to optimize component if you know that even if parent has changed, this component will not change.
React will execute your function component, compare it to the dom and will update if there are changes. If you use React.memo() your function component will not be executed again and it won't be compared to the dom.
So if you have a calculation in your function compoent that takes one second, without React.memo() it will run this calculation again.
Let's say I've triggered an update of a single React component & as we know by default it will trigger the update of all it's children components.
BUT
How does it work in combination with browser's reflow/repaint ?
How does the whole process look like (step by step) after we trigger a single React-component's update?
By default, the child components would be updated as well, however, that only happens in the virtualDOM, and not the actual DOM.
Changes are made to the virtualDOM, React then checks to see which DOM elements/components are changed/updated, and only those are updated in the actual DOM, it's part of the reason why your React app is fast.
You can refer to this thread for more information, though I think they are more so on class component, not functional component.
In a React component I am using an external library that creates complex components that I modify slightly on render. Thus, in my own component, I use things like element queries and mutation observers to get rendered elements in the DOM and dynamically add my own modifications, depending on the state of the DOM itself (not the external component, since I cannot access its state).
This works great, but I have not been able to figure out how to test this functionality [in Jest]. In particular, I add mutation listeners that add my own small React components based on the HTML that the external component renders, adding a button when the mouse hovers over a list of dynamically-created elements. When I attempt to test this in Jest, none of this logic is performed, and the functionality I have added cannot be tested, as the changes to the DOM do not appear, even with full rendering. In particular, during testing I have found that the queries I am using in the component do not have any values, as they need the external component to fully render the HTML for my own component to observe the changes.
I need a way to test my component in a way such that the external component is rendered, but such that my own component can perform updates afterwards, when its own state changes.
How can I test the functionality of the updates that I perform that are based on element queries if there are not any results to these queries during testing?
Consider the following example:
class GridContainer extends React.Component {
...
render (){
return <div>
<Pagination portalId="portal-id"></>
<Grid ...>
</div>
}
}
class Grid extends React.Component {
...
render (){
return <div>
<div id="portal-id"></>
<table ...>
</div>
}
}
class Pagination extends React.Component {
...
render (){
return return ReactDOM.createPortal(<div>Paginator DOM...</div>, document.getElementById(this.props.portalId));
}
}
Is it safe to render a portal inside other components DOM? I've tested it and it works, but I don't know if this is reliable. The Portals doc mention that you can render a portal in a DOM node but nothing about components DOM.
Why is this different (speculating here)? while updating the portal parent component, in the reconciliation process the diff might find the inconsistency and remove the portal node.
From my testing, the above doesn't happen but I don't know if I can assume that react handles it. So here comes the Q:
Is it safe to render a portal into another component DOM?
Is it safe? Sure, but it probably won't work the way you expect.
First off, you can totally dump dom inside a div that React created.
I've met several React programmers who would contest this fact, but Reacts design expects and accounts for editing dom directly when necessary. If they didn't, there would be no componentDidUpdate or React refs.
This documentation on integration with other libraries is probably the most relevant.
Here's the scoop:
React won't touch the internals of a rendered div, assuming it's always empty at the end of render. It will only:
Create new elements, which is irrelevant here as long as you leave it empty.
Update existing elements that were originally created by react.
Delete elements that were originally created by react.
So just create that empty div and leave it alone in render and React won't mess with it.
Here's the rub; React guarantees nothing about the timing of the renders.
This means that you have no idea if the element will actually be there when Pagination renders, causing the query to fail and the portal to not display. componentDidUpdate only works because React specifically runs it after the dom is updated. But render is run before the dom is updated. So if Pagination is rendered in the same sweep as Grid that div is likely not mounted yet.
Now the infamous stack overflow Just-Don't-Do-That answer:
Just don't do that. The purpose of portal is to let you render outside the React container while keeping your components inside of Reacts render tree. If you're rendering inside React render tree anyways why don't you just render the components there? (if that statement is confusing I blame you)
The Portals doc mention that you can render a portal in a DOM node but nothing about components DOM
This isn't mentioned because this is special case of general rule; DOM shouldn't be accessed directly in React if there are more idiomatic ways.
A lot of memory leaks occur in DOM. In case a component that hosts a portal (Grid) is re-rendered and portal component (Pagination) is not, this will result in detached DOM, i.e. memory leak.
An element where a portal is attached may not even exist at the time when portal component renders.
Can I in React (Native) force a component to take child components even if the component doest not.
I use a UI framework (elements) which does not support this on Buttons but I´d like to give it my custom spinning loading Icon Component and a Text Component.
What you want is Render Highjacking but it is quite complex and in my opinion not recommended. You are better off creating your own component.
https://medium.com/#franleplant/react-higher-order-components-in-depth-cf9032ee6c3e