React component render is called multiple times when pushing new URL
Solution 1
I would assume that this is normal. If you aren't having noticeable performance issues, I wouldn't sweat it. If performance begins to be a problem, you can look into overriding the shouldComponentUpdate
lifecycle method if you are certain that certain state changes won't change the rendered component.
Edit: You could also look into extending React.PureComponent
instead of React.Component
if you only need shallow comparison in your shouldComponentUpdate
lifecycle method. More info here.
Solution 2
If you are setting state at three different stages then the component will re-render three times as well.
setState() will always trigger a re-render unless conditional rendering logic is implemented in shouldComponentUpdate().
(source)
You can implement logic in shouldComponentUpdate() to prevent unneeded re-renders if you are experiencing performance issues.
Solution 3
This is an old question, I see, but I also noted this issue. Like noted in Donald's answer, it seems to be normal. I tried three things to troubleshoot my specific case:
- I turned off the React DevTools plugin to see if it was the cause of the duplicate messages.
- I checked a different browser to see if that was the issue.
- I created a short test to check if it happens on simple components.
The first two methods
Disabling the React DevTools plugin did not change the number of messages logged into the console.
Changing browser also had no effect. I tried Chromium and Firefox.
The third method
Even the simplest components seem to call the life cycle methods more than once.
Given two files, App.js
and components/TestComponent.js
, as follows:
// App.js
import React from 'react';
import './App.css';
import Test from './components/TestComponent';
function App() {
console.log('App render');
return (
<div>
<Test />
</div>
);
}
export default App;
// ./components/TestComponent.js
import React, { Component } from 'react';
class Test extends Component {
constructor(props) {
console.log('Test constructed');
super(props);
}
componentDidMount() {
console.log('Test mounted');
}
componentDidUpdate() {
console.log('Test updated');
}
render() {
console.log('Test rendered');
return (
<div>
<h1>Hello, world!</h1>
</div>
);
}
}
export default Test;
Life cycle methods of Test are called multiple times.
Notes
- I used create-react-app to set up the app.
- The react version is 16.13.1.
Results and discussion
With yarn start
, I get the following in the console:
App render
TestComponent.js:7 Test constructed
TestComponent.js:7 Test constructed
TestComponent.js:20 Test rendered
TestComponent.js:20 Test rendered
TestComponent.js:12 Test mounted
For me, at least, yarn
notes that the development build is not optimized, and running yarn build
and then serving it with python -m http.server --directory build
gives a page that doesn't have the duplicate messages.
As for why you're getting three renders instead of two, I can't say. My suggestion is to try building the app and seeing if the problem persists in the production build.
If you still encounter the issue, you can also go with Donald's suggestion to implement logic in shouldComponentUpdate
.
Solution 4
If using >v16.3, then try removing <React.StrictMode> and it should work fine.
Why? Since v16.3 for class components and v16.8 for hooks , React introduced <React.StrictMode> in order to make the transition to Concurrent React ( in the near future ) more developer friendly, since render phase can be invoked multiple times then.
The following articles are read worthy:
React Components rendered Twice
React Components render twice and drive me crazy
Wait, you're not using <React.StrictMode>?!
Note: This is applicable to dev env only.
Related videos on Youtube
egidra
Updated on July 09, 2022Comments
-
egidra almost 2 years
I am building a PhotoViewer that changes photos when the user presses left or right. I am using React, Redux, react-router, and react-router-redux. When the user presses left or right, I do two things, I update the url using
this.context.replace()
and I dispatch an action to update the currently viewed photo,this.props.dispatch(setPhoto(photoId))
. I am subscribing to state changes for debugging.Each of the above lines triggers a new state change. Dispatching an action updates the store since I update the
currentlyViewedPhoto
and updating the url updates the store because react-router-redux updates the url in the store. When I dispatch the action, in the first rerendering cycle, the component'srender
function gets called twice. In the second rerendering cycle, the component'srender
function gets called once. Is this normal? Here is the relevant code:class PhotoViewer extends Component { pressLeftOrRightKey(e) { ... code to detect that left or right arrow was pressed ... // Dispatching the action triggers a state update // render is called once after the following line this.props.dispatch(setPhoto(photoId)) // assume photoId is correct // Changing the url triggers a state update // render is called twice this.context.router.replace(url) // assume url is correct return } render() { return ( <div>Test</div> ) } } function select(state) { return state } export default connect(select)(PhotoViewer)
Is this normal that render is called three times? It seems like overkill because React will have to do the DOM diffing three times. I guess it won't really matter because nothing has changed. I am new to this toolset, so feel free to ask any more questions about this problem.
-
Marc Stober over 7 yearsI had an issue with not having slashes in my links. If I had
<Link to="foo">
, React router (not using redux) was "redirecting" from#foo
to#/foo
and causing an extra render. Adding the slash to the link fixed it. This is using hashHistory.
-
-
egidra over 8 yearsI could understand if there were two re-renders (from the dispatch action and the url replacement), but three is kind of concerning to me. The url replacement causes two updates, instead of one. Does react-router-redux make two updates to the store or something?
-
egidra over 8 yearsThat's good to know that it is normal. This is my first time using this architecture, and it was really concerning to me that render was being fired multiple times.
-
villeaka over 8 yearsI haven't personally used react-router-redux so I can't unfortunately answer that. You could try logging state mutations inside your store or
shouldComponentUpdate
and see what's changing. -
Donald over 8 yearsTotally understandable - for a situation like this, you really won't begin to see performance issues until you have very complex components.
-
grantwparks almost 8 yearsI find this to be indefensible. Complacency with "just run whatever however many times with the same arguments and results unless you get a problem".
-
Dexygen over 5 yearsI too am new to React and was surprised that
render()
was getting called twice, and oh BTW switching toPureComponent
made no difference :( -
adrian over 2 yearsRepeated answer
-
kirjosieppo over 2 yearsThis does not provide an answer to the question. Once you have sufficient reputation you will be able to comment on any post; instead, provide answers that don't require clarification from the asker. - From Review