Debug react component rerender - javascript

I'm trying to debug bug that is reproduced very rarely (once per several dozens of trys).
I'm inside of render call and want to find out as much information as possible from there:
What caused rerender: forceUpdate, setState or props changed?
If it was a props change, which component initiated chain of rerenders: I mean not the fact of parent render, but the top component from parents chain that has used setState or forceUpdate and so caused rerender of itself and the whole tree bellow (including the component I'm currently in).
It's guaranteed that all components are class components (not functional) and I'm using react 16.4.2 including deprecated lifecycle methods (if it is important). There are some usages of context too.
How can I make it? Note, I'm asking about debug techniques, not about fixing my concrete bug.

If your component is a pure component - extends React.PureComponent { ... }, you don't really have to care about the whole chain of re-renders, since it will re-render only if props have changed (from the chain or from the redux store).
It will not re-render if parent state changed or if parent basically has re-rendered.
However, it will still re-render - as I mentioned above - if props have changed or state inside that component was updated or forceUpdate function was called.
If you are not calling forceUpdate inside your component or you are not updating the state, the issue may be related with the props.
You could use e.g. componentDidUpdate and simply compare the prevProps with this.props and check which one of the props has changed.
Nonetheless, you can also check https://www.npmjs.com/package/#welldone-software/why-did-you-render package, it might be helpful for you.

Related

react js - key vs componentshouldupdate

I know using "key" prop on any React component will re-mounts if there is a change in key value.
Using "ComponentShouldUpdate" lifecycle method will just update the component instead of re-render.
In what cases we should use "key" vs "ComponentShouldUpdate"? Does using one provides advantage over other ?
I think you should revisit the documentation because what you know is not correct.
a component gets updated when props or state change no matter if you have keys or not in the component
shouldComponentUpdate gets executed every time before render and tells if the component should be re-rendered or not. for regular components the method just returns true. you can overwrite it. pure components do a shallow check.
keys only help react know what changed during a render/re-render. they don't stop/prohibit a re-render.
You should use shouldComponentUpdate as a optimization.
key and componentDidUpdate are used for entirely difference purposes.
From the docs,
React implements a heuristic O(n) algorithm based on two assumptions:
Two elements of different types will produce different trees.
The developer can hint at which child elements may be stable across
different renders with a key prop.
What this means is that if a key passed to a react component changes, react will tear down the old tree represented by the component at DOM and create a new tree(unmount and then remount the component even if nothing has changed except the key).
On the other hand, componentDidUpdate will run after a component has been updated i.e a prop or state for the specific component has changed. Update will not result in the teardown of the tree from the state.
You should not be using key in usual cases and let props/state changes trigger componendDidUpdate and handle your logic there. Key is used on some occassions where you have a large amount of state logic and you want to reset your state logic to initial state i.e remount your component from scratch. Essentially, you should avoid using key to unmount and remount your component as this operation affects performance.

Redux: How do partial re-renderings work?

This question is about internals for partial re-renderings with React-Redux.
To explain what I mean, I will first introduce a very crude technique for managing state without any state management libary.
The technique uses a a huge "AppState"-object that is owned by the top-level App-component.
Suppose that this AppState holds not only state-properties, but also several callbacks that mutate those state-properties.
Furthermore, suppose that we use props to pass down this AppState throughout the entire component hierarchy.
Thanks to the ES6-spread syntax, passing a huge number of props can be done without a lot of boilerplate code.
In the top-level App-component, it will look like this:
<ChildComponent {...this.state} />
In all other components, it will look like this:
<GrandChildComponent {...this.props} />
It is important to note that the ES6-spread syntax does not actually pass the AppState-object. Instead, it extracts all the AppState-properties and passes them as separate props.
Now we should distinguish between top-level properties and nested child-properties of the AppState:
If I mutate a top-level property of this AppState by calling setState, then the entire app will re-render (unless I use things like pure components).
However, if I change a nested child-property of this AppState, then nothing will happen because React does not notice the property change.
This leads to my final questions:
What is the render-performance of this crude approach in comparison to Redux?
How exactly does Redux handle "partial renderings", such that only some of the Components re-render after a state mutation?
If I mutate a top-level property of this AppState by calling setState, then the entire app will re-render (because everything depends on the AppState).
If you mutate and use pure components then nothing will render, you change state by creating a new state object.
However, if I mutate a nested child-property of this AppState, then nothing will happen because React does not notice the property change.
This is only true if you mutate and components are pure.
What is the render-performance of this crude approach in comparison to Redux?
Prop drilling will re render the entire tree but branches that use state that didn't change won't re render if they are pure. Prop drilling is bad for maintenance because if you need to refactor grand child state logic you may need to refactor the whole tree or branch. But from a performance point it would not take a big hit provided that you use pure components and are careful when passing callbacks and not re creating them on every render (see useCallback).
How exactly does Redux handle "partial renderings", such that only some of the Components re-render after a state mutation?
React-redux useSelector or connect mapStateToProps are always called every time dispatch changed state and before rendering.
If the result is different than last result then react-redux will trigger render of the component. If the component gets props then a render could also be triggered because props change and mapstate/selector will be executed.
A connected component will observe state and render when the result of mapState or selector has changed. An example app with logs showing what react-redux will execute can be found here
For state management, you don't necessarily have to use Redux, if your use cases are small, maybe React Hook would be perfect for you.
For React rerendering matter, what I know is there are several strategies (useMemo, PureComponents) provided by React for managing and improve the performance. It really depends on how you manage your components.
One example is using PureComponent, even if you have a large state in your top-level app.js, if you manage the child components properly, they will not re-render if their receiving props haven't changed.

Is it possible to detect the cause of getDerivedStateFromProps in React-Redux?

I have observed that the getDerivedStateFromProps of the React Component is called in at least 2 cases:
when the props are changed, e.g. the component imports Redux store data via component's props when the Redux store have received new data from the external API (either as a result from the request initiated by the component or as a push from external event)
when the component's setState is called, e.g. user can update data in some element of the component and this update is handled by the procedure that calls setState.
it is also called during the navigation, when props.match.params.... are changed.
So - I would like determine the cause (1. or 2.) of the getDerivedStateFromProps and make distinct actions in each case. How it is possible to make such distinction. Maybe this is not possible to do. Or maybe my architecture is flawed if I wish to do this?
The main problem for me is - how to pass business object from the redux store (to which the props of component points to) into this.state of some component for further local manipulation?
My previous attempt is documented in the question ReactJS setState conflicts with getDerivedStateFromProps in which the more concrete code examples are available.

componentWillReceiveProps isn't called until component is focused, is it something I've done?

I have a ReactJS component that I'm developing which needs to get some information from the URL. To do this I've been utilizing the componentWillReceiveProps lifecycle method to look at props.location.query and dispatches actions to a Redux store in order to update the known state. The problem that I'm running into is that it doesn't appear that componentWillReceiveProps is being called for my component until that component has focus. I can reload the page which hosts this component and the render is called but componentWillReceiveProps is never called first.
Clearly I'm either understanding the lifecycle incorrectly with respect to componentWillReceiveProps or there is something else either wrong in my component or application which is make it behave differently than it is intended. Please set me straight either way.
componentWillReceiveProps isn't called on the first render.
From the React Docs:
"Invoked when a component is receiving new props. This method is not called for the initial render."

Caching props in getDefaultProps an anti-pattern in React?

I am writing a complex react app and using Cortex as my central model. The philosophy with cortex is that it wraps your data and on changing the data, calls a complete re-render from the root. This works great especially when you have non hierarchical views changing state and affecting the other.
The issue that I am facing is maintaining states/props on re-render. For example I have a certain hierarchy which goes like this:
<Page>
<EditorCard>
<Editor/>
<PublishButton/>
</EditorCard>
</Page>
The EditorCard needs the JavaScript instance of the Editor in order to make changes to the Editor on clicking the PublishButton (I am using an external library inside Editor which exposes methods for editing). Hence the Editor on ComponentDidMount sets the instance as a prop on the EditorCard by calling a function passed down to it.
My issue is that when I click the PublishButton I change the value of the cortex object which causes a re-render from the root and I loose the props for that Editor (since component is already mounted ComponentDidMount is not called again).
The way I took care of this problem is by caching of getDefaultProps.
Inside EditorCard my default props are:
getDefaultProps: function() {
return {
cachedData: {},
}
},
And is saving the editor instance as this.props.cachedData.editor = editorInstance
This saves props over multiple re-renders.
Is this how getDefaultProps caching was meant to be used? On saving props over multiple re-renders am I breaking some of the core react rules with this hack? Could you suggest a better structure if so?
No, getDefaultProps is what it means to be: getting the default props in case the owner hasn't passed those to you. You could say it's a shorthand for a = this.props.bla || 'hello';.
That being said, if I'm understand your question correctly, I see three ways to solve it.
Cache that in your state instead. Props are passed by the parent and are meant to be read from, inside the child, at least in vanilla React.
Instead of putting that props passing logic in your componentDidMount, why not put it in componentDidUpdate?
ref lets you grab the instance and call its methods directly.

Categories