I have a parent component, with many nested children components inside.
A click on one of my children's components updates the route. The route property is watched on the parent component, and does some actions on change.
This can be extremely difficult to debug if I don't know which component contains the watcher. Is there a way to see which watchers get executed?
Not sure if it helps but you may use the devtools to see which components emit something.
On top of that, you could probably console.log in the watch or emit some additional payload to identify the component more easily.
Related
In our experience, thinking about how the UI should look at any given moment, rather than how to change it over time, eliminates a whole class of bugs.
From React Docs
From my understanding, this means that React only updates what's necessary, rather than destroying and re-constructing the entire DOM tree again. Am I wrong?
Can anyone please help me understand the quoted statement?
Thanks.
From my understanding, this means that React only updates what's necessary, rather than destroying and re-constructing the entire DOM tree again. Am I wrong?
If you want to know the short answer, I have to say it is true, React will update the necessary elements in DOM whenever it needed.
But if you want to know how it's done, and when React will update the DOM and its element I have to it is varying to different several things, like project architecture, using proper methods (proper hooks in functional component eg. useCallback, useMemo, and so on) and so on.
When it truly gets rerender then?
As far as I know, there are two ways React finds out when to rerender the DOM.
Passing elements to ReactDOM.render
Update a state
What is ReactDOM.render?
This will call the render() method from react-dom (Where we usually import it as ReactDOM) and it will render a React element into the DOM in the supplied container and return a reference to the component (or returns null for stateless components). Also if the React element was previously rendered into the container, this will perform an update on it and only mutate the DOM as necessary to reflect the latest React element.
What does state mean?
The state object is where you store property values that belong to the component. So when you got a component and that component has their own specific variables where changing them should affect the DOM you should use it, then whenever state gets changes the component will be updated.
So what I even talk about project architecture and this stuff, when I didn't mention anything about it above?
Let's say we got a project with one parent component and 3 child component just like this:
Component 1
- |- Component 2
- - |- Component 3
- - - |- Component 4
So whenever you a state in Component 4 all of the DOM elements will be get rerendered, why then? Because Component 4 is a child of Component 3 and so on, so when the child state gets change it will force the parent to rerender then the whole DOM will rerender once per state change.
Final Note
So, at last, we should be always considered a good architecture and hierarchy for our project or when it necessarily use built-in methods like useMemo to avoid such a thing.
Let's say we have a parent component and multiple functional child components. I want to clearly know if the parent re-renders does the child re-renders or not.
After going through a few articles I came to know there are 3 ways we can detect rerenders. (Let me know if there are more ways.)
1. Put a console.log in the child component.
2. Use Chrome paint flashing option in the settings.
3. Use React dev tool
Do all these ways are correct to know if the component really rerenders? Because it doesn't seem to be work correctly with React.memo.
When I am wrapping the Child component with React.memo it does not print console.log, when the parent component rerenders which is correct. But still with chrome and react dev tools highlights the child component as if it rerendered.
CodeSandbox: https://codesandbox.io/s/bold-cloud-iv0rv
(If we add a new car still the static component is highlighted in green, but as per Memo, it should not rerender.)
Now my doubt, Is paint flashing does not work correctly or React.memo having issues?
Reason
If you use React.memo, you need to use it from parent down to all the child till the end.
Since React.PureComponent share the same feature with React.memo, you can find those explanation in the document as below.
Furthermore, React.PureComponent’s shouldComponentUpdate() skips prop updates for the whole component subtree. Make sure all the children components are also “pure”.
Result
By changing parent component Cars to memo
// Before
export default Cars;
// After
export default React.memo(Cars);
You could find the react-dev-tools in chrome will only show the parent component re-rendered this time as well as no child console.log fired, which is correct. (Compare to previous, all the child also got highlighted)
Before
After
Conclusion
Both console.log and react-dev-tools worked well, you may just need to implement in a proper way following your demand.
lHello everyone, here is the problem.
We have a grid component with some filtering enabled. When the filtering is applied, if a certain callback-prop exists, it is called with the filtered data as an argument.
The problem is this. If said datagrid is wrapped by a parent component and the parent component saves the filtered data in it's state, it causes the parent to rerender, but also the datagrid. However, when the datagrid renders it runs it's filtering logic, which causes the callback(which is setState() call) to run.
So, to avoid the loop I introduced a variable to the parent component class and save the data there, but it doesn't seem so good to me.
Another option would be redux, just add a new action and dispatch it when the filtering runs.
Any other ideas?
Since you're also asking for other ideas, may I suggest React hooks. They allow finer-grained control, such as multiple states, reducers, memoized callbacks, effects that are only called when inputs change, etc.
I have a large array that I am using in a component (component A) with *ngFor with a nested *ngFor.
Component B initialises a jquery plugin which registers a document mousemove event handler, I am using this.zone.runOutsideAngular to init the plugin and I am calling this.ref.detectChanges() in the callback as I need to update the UI on mousemove inside the component B.
Component A is not a child of component B.
As soon as the component A is rendered change detection becomes very slow. the array does not change and I am using the ChangeDetectionStrategy.OnPush strategy for component A but when I fire ref.detectChanges() inside component B, ngDoCheck gets called on component A and I can see a noticeable jank on mousemove.
Is there a way to tell angular to completely ignore the large array of items in component A and allow me to handle when the UI should be updated? I thought that using ChangeDetectionStrategy.OnPush would give me what I need but I have tried removing all #Input()s from component A and anytime I call this.ref.detectChanges() inside component B it is still firing ngDoCheck and it is obvious that this is very slow.
I can scroll through the list of items no issue, but it is when I am triggering the detectChanges inside the mousemove on component B that is causing the issue. I know I could manually update the DOM but I think this would just be a workaround as it would only address the jank on mousemove and not the issue around the change detection being slow.
I have got to the bottom of this issue.
The problem was that inside component A for the nested *ngFor I was using a child component to render each sub item which meant that although I was using the ChangeDetectionStrategy.OnPush strategy, it still required a ref check for each item.
I have now moved the html from the child component into component A directly and this has had a huge impact on performance.
this.ref.detach() to remove the detector from from the tree completely, that should stop the checking. Then you can still call detectChanges to do it manually, and reattach to bring it back online.
Maybe also debouncing the mousemoves (rxjs debounceTime()) might help, unless you really need to track every mousemove?
One more optimization if you already didn't, add trackBy: yourTrackByFn to the ngFor(s).
I have a very complex object. A parent component passes this down to its child component. The child component then passes various parts of this complex object to its own children. Sometimes these children (parent's grandchildren) then pass it down yet again.
I need the parent to detect if the object has changed. The conventional wisdom I've seen is that the child should emit an event when something has changed. The object I'm dealing with is large/complex, and this object can be modified by children/grandchildren/great-grandchildren, so it's a bit difficult to keep track of when something has changed and have to bubble it up multiple times.
Is there any way for the parent to just always know if the object has been modified?
Use observables in this complex object and emit changes through this observables when something changes. This way every interested party can subscribe to changes.
See https://angular.io/docs/ts/latest/cookbook/component-communication.html for examples.