score:138
you can check the reason for a component's (re)render with the react devtools profiler tool. no changing of code necessary. see the react team's blog post introducing the react profiler.
first, go to settings cog > profiler, and select "record why each component rendered"
score:1
the above answers are very helpful, just in case if anyone is looking for a specfic method to detect the cause of rerender then i found this library redux-logger very helpful.
what you can do is add the library and enable diffing between state(it is there in the docs) like:
const logger = createlogger({
diff: true,
});
and add the middleware in the store.
then put a console.log()
in the render function of the component you want to test.
then you can run your app and check for console logs.wherever there is a log just before it will show you difference between state (nextprops and this.props)
and you can decide if render is really needed there
it will similar to above image along with the diff key.
score:3
thanks to https://stackoverflow.com/a/51082563/2391795 answer, i've come up with this slightly different solution for functional components only (typescript), which also handles states and not only props.
import {
useeffect,
useref,
} from 'react';
/**
* helps tracking the props changes made in a react functional component.
*
* prints the name of the properties/states variables causing a render (or re-render).
* for debugging purposes only.
*
* @usage you can simply track the props of the components like this:
* userenderingtrace('mycomponent', props);
*
* @usage you can also track additional state like this:
* const [somestate] = usestate(null);
* userenderingtrace('mycomponent', { ...props, somestate });
*
* @param componentname name of the component to display
* @param propsandstates
* @param level
*
* @see https://stackoverflow.com/a/51082563/2391795
*/
const userenderingtrace = (componentname: string, propsandstates: any, level: 'debug' | 'info' | 'log' = 'debug') => {
const prev = useref(propsandstates);
useeffect(() => {
const changedprops: { [key: string]: { old: any, new: any } } = object.entries(propsandstates).reduce((property: any, [key, value]: [string, any]) => {
if (prev.current[key] !== value) {
property[key] = {
old: prev.current[key],
new: value,
};
}
return property;
}, {});
if (object.keys(changedprops).length > 0) {
console[level](`[${componentname}] changed props:`, changedprops);
}
prev.current = propsandstates;
});
};
export default userenderingtrace;
note the implementation itself hasn't changed much. the documentation shows how to use it for both props/states and the component is now written in typescript.
score:6
using hooks and functional components, not just prop change can cause a rerender. what i started to use is a rather manual log. it helped me a lot. you might find it useful too.
i copy this part in the component's file:
const keys = {};
const checkdep = (map, key, ref, extra) => {
if (keys[key] === undefined) {
keys[key] = {key: key};
return;
}
const stored = map.current.get(keys[key]);
if (stored === undefined) {
map.current.set(keys[key], ref);
} else if (ref !== stored) {
console.log(
'ref ' + keys[key].key + ' changed',
extra ?? '',
json.stringify({stored}).substring(0, 45),
json.stringify({now: ref}).substring(0, 45),
);
map.current.set(keys[key], ref);
}
};
at the beginning of the method i keep a weakmap reference:
const refs = useref(new weakmap());
then after each "suspicious" call (props, hooks) i write:
const example = useexamplehook();
checkdep(refs, 'example ', example);
score:8
strange nobody has given that answer but i find it very useful, especially since the props changes are almost always deeply nested.
hooks fanboys:
import deep_diff from "deep-diff";
const withpropschecker = wrappedcomponent => {
return props => {
const prevprops = useref(props);
useeffect(() => {
const diff = deep_diff.diff(prevprops.current, props);
if (diff) {
console.log(diff);
}
prevprops.current = props;
});
return <wrappedcomponent {...props} />;
};
};
"old"-school fanboys:
import deep_diff from "deep-diff";
componentdidupdate(prevprops, prevstate) {
const diff = deep_diff.diff(prevprops, this.props);
if (diff) {
console.log(diff);
}
}
p.s. i still prefer to use hoc(higher order component) because sometimes you have destructured your props at the top and jacob's solution doesn't fit well
disclaimer: no affiliation whatsoever with the package owner. just clicking tens of times around to try to spot the difference in deeply nested objects is a pain in the.
score:12
@jpdelatorre's answer is great at highlighting general reasons why a react component might re-render.
i just wanted to dive a little deeper into one instance: when props change. troubleshooting what is causing a react component to re-render is a common issue, and in my experience a lot of the times tracking down this issue involves determining which props are changing.
react components re-render whenever they receive new props. they can receive new props like:
<mycomponent prop1={currentposition} prop2={myvariable} />
or if mycomponent
is connected to a redux store:
function mapstatetoprops (state) {
return {
prop3: state.data.get('savedname'),
prop4: state.data.get('usercount')
}
}
anytime the value of prop1
, prop2
, prop3
, or prop4
changes mycomponent
will re-render. with 4 props it is not too difficult to track down which props are changing by putting a console.log(this.props)
at that beginning of the render
block. however with more complicated components and more and more props this method is untenable.
here is a useful approach (using lodash for convenience) to determine which prop changes are causing a component to re-render:
componentwillreceiveprops (nextprops) {
const changedprops = _.reduce(this.props, function (result, value, key) {
return _.isequal(value, nextprops[key])
? result
: result.concat(key)
}, [])
console.log('changedprops: ', changedprops)
}
adding this snippet to your component can help reveal the culprit causing questionable re-renders, and many times this helps shed light on unnecessary data being piped into components.
score:83
here are some instances that a react component will re-render.
- parent component rerender
- calling
this.setstate()
within the component. this will trigger the following component lifecycle methodsshouldcomponentupdate
>componentwillupdate
>render
>componentdidupdate
- changes in component's
props
. this will triggercomponentwillreceiveprops
>shouldcomponentupdate
>componentwillupdate
>render
>componentdidupdate
(connect
method ofreact-redux
trigger this when there are applicable changes in the redux store) - calling
this.forceupdate
which is similar tothis.setstate
you can minimize your component's rerender by implementing a check inside your shouldcomponentupdate
and returning false
if it doesn't need to.
another way is to use react.purecomponent
or stateless components. pure and stateless components only re-render when there are changes to it's props.
score:406
if you want a short snippet without any external dependencies i find this useful
componentdidupdate(prevprops, prevstate) {
object.entries(this.props).foreach(([key, val]) =>
prevprops[key] !== val && console.log(`prop '${key}' changed`)
);
if (this.state) {
object.entries(this.state).foreach(([key, val]) =>
prevstate[key] !== val && console.log(`state '${key}' changed`)
);
}
}
here is a small hook i use to trace updates to function components
function usetraceupdate(props) {
const prev = useref(props);
useeffect(() => {
const changedprops = object.entries(props).reduce((ps, [k, v]) => {
if (prev.current[k] !== v) {
ps[k] = [prev.current[k], v];
}
return ps;
}, {});
if (object.keys(changedprops).length > 0) {
console.log('changed props:', changedprops);
}
prev.current = props;
});
}
// usage
function mycomponent(props) {
usetraceupdate(props);
return <div>{props.children}</div>;
}
Source: stackoverflow.com
Related Query
- Trace why a React component is re-rendering
- Why is my React component is rendering twice?
- Why is this react component rendering twice?
- Why is my react component rendering twice on initial load?
- Why is my React Component Not Rendering HTML, but logs correctly?
- Why React Component is rendering on same page instead of another?
- Why is my React component rendering my JSX as text rather than HTML?
- Why is React rendering my component over and over with an unchanged state?
- Why is my react component not rendering only when using routes? react-router-domV.6
- Why is my React component rendering twice?
- Why isn't my React Component Rendering Images?
- Why is this React component rendering infinitely?
- Why is this React Component rendering first?
- Why is React not rendering my component state correctly?
- Why is my react component not re rendering after dispatching an action that changes the redux store?
- Why is only the first React component rendering in my multi-page in Django app?
- Why isn't child component rendering when testing with React Testing Library?
- Understanding why super() is deprecated in a React class component
- Dynamically Rendering a React component
- Why does React warn against an contentEditable component having children managed by React?
- Why is `Promise.then` called twice in a React component but not the console.log?
- Why IE 11 display blank page rendering react app
- My React Component is rendering twice because of Strict Mode
- Why does my React Component Export not work?
- Prevent react component from rendering twice when using redux with componentWillMount
- Simple React component not rendering
- Why do I have to .bind(this) for methods defined in React component class, but not in regular ES6 class
- Rendering react component after api response
- Rendering a React component inside a Bootstrap popover
- How to test decorated React component with shallow rendering
More Query from same tag
- React-redux : listening to state changes to trigger action
- Test conditional rendering of components based on ContextAPI data using Jest and Enzyme
- 404 when trying to enter a react app route
- ReactJS onClick not firing
- cd to correct folder in package.json
- How to have searchable dropdown in Redux-form
- React-Router: Nesting routes without nesting components with wildcard paths
- Use reselect selector with parameters
- Material UI: Menu refactoring
- ReactJS: Data Transformation with JSX
- "Uncaught ReferenceError: require is not defined" when importing into App.js for React App created using CDN links
- Reactjs call component/function from built app
- Looping through the keys collection
- How to calculate numbers within an array of objects
- useTransition with react-spring as a component changes
- React Native - LayoutAnimation: how to make it just animate object inside component, not whole component/view?
- Display React properties by Id
- JavaScript array filtering based on any combination of properties
- Got a blank white page after deploying react app to gitlab pages
- how to call action after every 2 minute in reactjs with await
- Cannot assign to read only property 'backgroundColor' of object '#<Object>'
- Why is this variable both empty and not empty according to the class state's logic?
- How can I ignore empty parameters in express application
- How to switch multiple react components on same page
- React-select - Is there a way to load values only on typing the characters
- material-ui 4.3.2 context menu mouse right click position
- Jest react testing: Check state after delay
- Typescript: Different Types in different classes with same variable
- Console log not responding on handle change in ReactJS
- React: Execute some check before render