652

Does React re-render all components and sub components every time setState() is called?

If so, why? I thought the idea was that React only rendered as little as needed - when state changed.

In the following simple example, both classes render again when the text is clicked, despite the fact that the state doesn't change on subsequent clicks, as the onClick handler always sets the state to the same value:

this.setState({'test':'me'});

I would've expected that renders would only happen if state data had changed.

Here's the code of the example, as a JS Fiddle, and embedded snippet:

var TimeInChild = React.createClass({
    render: function() {
        var t = new Date().getTime();

        return (
            <p>Time in child:{t}</p>
        );
    }
});

var Main = React.createClass({
    onTest: function() {
        this.setState({'test':'me'});
    },

    render: function() {
        var currentTime = new Date().getTime();

        return (
            <div onClick={this.onTest}>
            <p>Time in main:{currentTime}</p>
            <p>Click me to update time</p>
            <TimeInChild/>
            </div>
        );
    }
});

ReactDOM.render(<Main/>, document.body);
<script src="https://cdnjs.cloudflare.com/ajax/libs/react/15.0.0/react.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/react/15.0.0/react-dom.min.js"></script>
HoldOffHunger
  • 18,769
  • 10
  • 104
  • 133
Brad Parks
  • 66,836
  • 64
  • 257
  • 336
  • I had the same issue, I don't know the exact solution. But I had cleaned up the unwanted codes from the component it started working as usual. – Jaison James Dec 12 '18 at 11:56
  • I would like to point out that in your example - because how your element is designed does not solely rely on a unique state - calling `setState()` even with dummy data does cause the element to render differently so I would say yes. Absolutely it should try to re-render your object when something might have changed because otherwise your demo - assuming it was the intended behaviour - wouldn't work! – Tadhg McDonald-Jensen Jan 28 '19 at 17:13
  • You may be right @TadhgMcDonald-Jensen - but from my understanding, React would've rendered it the first time (since state changes from nothing to something that first time), then never had to render again. I was wrong though, of course - as it looks like React requires you to write your own `shouldComponentUpdate` method, which I assumed a simple version of it must already be included in React itself. Sounds like the default version included in react simply returns `true` - which forces the component to re-render every single time. – Brad Parks Jan 29 '19 at 12:48
  • Yes but it only needs to re-render in the virtual DOM then it only changes the actual DOM if the component is rendered differently. Updates to the virtual DOM are usually negligible (at least compared to modifying things on the actual screen) so calling render every time it might need to update then seeing that no change has happened not very expensive and safer than assuming it should render the same. – Tadhg McDonald-Jensen Feb 01 '19 at 17:57

10 Answers10

668

Does React re-render all components and sub-components every time setState is called?

By default - yes.

There is a method boolean shouldComponentUpdate(object nextProps, object nextState), each component has this method and it's responsible to determine "should component update (run render function)?" every time you change state or pass new props from parent component.

You can write your own implementation of shouldComponentUpdate method for your component, but default implementation always returns true - meaning always re-run render function.

Quote from official docs http://facebook.github.io/react/docs/component-specs.html#updating-shouldcomponentupdate

By default, shouldComponentUpdate always returns true to prevent subtle bugs when the state is mutated in place, but if you are careful to always treat the state as immutable and to read-only from props and state in render() then you can override shouldComponentUpdate with an implementation that compares the old props and state to their replacements.

Next part of your question:

If so, why? I thought the idea was that React only rendered as little as needed - when the state changed.

There are two steps of what we may call "render":

  1. Virtual DOM renders: when render method is called it returns a new virtual dom structure of the component. As I mentioned before, this render method is called always when you call setState(), because shouldComponentUpdate always returns true by default. So, by default, there is no optimization here in React.

  2. Native DOM renders: React changes real DOM nodes in your browser only if they were changed in the Virtual DOM and as little as needed - this is that great React's feature which optimizes real DOM mutation and makes React fast.

Ankit
  • 49
  • 1
  • 12
Petr
  • 7,275
  • 2
  • 16
  • 16
  • 63
    Great explanation! And the one thing that really makes React still shine in this case is that it doesn't change the *real* DOM unless the virtual DOM has been changed. So if my render function returns the same thing 2 times in a row, the real DOM doesn't get changed at all... Thanks! – Brad Parks Feb 09 '15 at 13:58
  • Does replaceState more effective? – muyiou Oct 30 '15 at 08:07
  • 1
    I think __@tungd__ is right - see his answer below. It is also a matter of a parent-child relation between components. For example if __TimeInChild__ is a sibling of __Main__ then its __render()__ will not be called unnecessarily. – gvlax Nov 18 '15 at 12:09
  • 3
    If your state contains a relatively large javascript object (~1k total properties), which is rendered as a large tree of components (~100 total)... should you let the render functions construct the virtual dom, or should you, before setting the state, compare the new state to the old manually and only call `setState` if you detect there's a difference? If so, how to do this best - compare the json strings, construct and compare object hashes,...? – Vincent Sels Feb 26 '16 at 12:33
  • So, overriding `shouldComponentUpdate ` will only have performance improvement at step#1, which only means not to reconstruct the virtual dom tree structure in some cases? – JaskeyLam Apr 20 '16 at 02:31
  • @Jaskey yes, ``shouldComponentUpdate`` help us not to recostruct the virual dom tree structure in some cases (step#1 as described above). It also means because we do not recostruct the virtual dom (when ``shouldComponentUpdate`` returned false), React under the hood do not touch the real browser DOM also (step#2) and this is a huge performance improvement! – Petr Apr 20 '16 at 13:39
  • 1
    @Petr , but even though react reconstruct the virtual dom, if the old virtual dom is the same as new virtual dom, the browser dom will not be touched , isn't it? – JaskeyLam Apr 21 '16 at 03:54
  • 3
    Also, look into using React.PureComponent (https://reactjs.org/docs/react-api.html#reactpurecomponent). It only updates (re-renders) if the component's state or props have actually changed. Beware, however, that the comparison is shallow. – debater Feb 15 '18 at 10:40
  • @Brad Parks, if due to a single component which affects the state of parent component (includes nth child - component) how react respond to this change, will it render whole dom or just the component using the state variable? – KumailR Jun 20 '19 at 12:57
  • @smkrn110 - not sure - I'm not deep into React recently - I'd ask someone else! My feeling is just the component (DOM Element) that's changed – Brad Parks Jun 20 '19 at 12:59
  • Sorry, I dont quite understand the last part of your explanation. does that mean React always renders a new structure of the DOM when setState is called, but unless there are actual differences visual differences than it would be updated to the actual DOM? – Brandon Feb 03 '20 at 17:23
  • React doesn't re-render if you call `setState` with the same value as the current state. – JMadelaine Feb 14 '20 at 01:58
  • That means, if you ever set the state using `setXX()` function returned from `useState()` hook using the same value for XX, then React enters an infinite loop of re-renders. – Emre Tapcı Sep 04 '20 at 10:01
137

No, React doesn't render everything when the state changes.

  • Whenever a component is dirty (its state changed), that component and its children are re-rendered. This, to some extent, is to re-render as little as possible. The only time when render isn't called is when some branch is moved to another root, where theoretically we don't need to re-render anything. In your example, TimeInChild is a child component of Main, so it also gets re-rendered when the state of Main changes.

  • React doesn't compare state data. When setState is called, it marks the component as dirty (which means it needs to be re-rendered). The important thing to note is that although render method of the component is called, the real DOM is only updated if the output is different from the current DOM tree (a.k.a diffing between the Virtual DOM tree and document's DOM tree). In your example, even though the state data hasn't changed, the time of last change did, making Virtual DOM different from the document's DOM, hence why the HTML is updated.

Ankit
  • 49
  • 1
  • 12
tungd
  • 14,467
  • 5
  • 41
  • 45
  • 1
    Yes, this is the correct answer. As an experiment modify the last line as __React.renderComponent(
    , document.body)__; and remove ____ from the body of __render()__ of the __Main__ component. The __render()__ of __TimeInChild__ will not be called by default because it is not a child of __Main__ any more.
    – gvlax Nov 18 '15 at 11:58
  • Thanks, stuff like this is a little bit tricky, that's why the React authors recommended that the `render()` method should be "pure" - independent of outer state. – tungd Nov 19 '15 at 01:29
  • 3
    @tungd, what does it mean `some branch is moved to another root`? What do you call `branch`? What do you call `root`? – Green Jul 31 '16 at 20:38
  • 2
    I really prefer the answer marked as the correct one. I understand your interpretation of 'rendering' on the native, 'real', side... but if you look at it from the react-native side you must say that it renders again. Luckily it is smart enough to determine what really changed and only update these things. This answer might be confusing for new users, first you say no, and then you explain that things do get rendered... – WiRa Jan 27 '17 at 09:53
  • 1
    @tungd can u please explain Green's question `what does it mean some branch is moved to another root? What do you call branch? What do you call root? ` – madhu131313 Aug 20 '18 at 08:10
  • @ᚔZenOutᚔ: We call the DOM tree, root means parent element, branch means child element. I meant to describe the situation where `
      ` -> `
        `, ideally it could just move the `
      • ` however most likely it will destroy the old and create a new one. – tungd Oct 25 '18 at 14:54