How to tell when React updates the real DOM

AndroidDev

I'm just starting to learn React JS and am going through the tutorial on building the Tic Tac Toe game:

https://reactjs.org/tutorial/tutorial.html

I notice that if I put a breakpoint in the code where the Game component gets rendered, it gets called every time you click on a square in the game. At first I thought that this is bad performance but found out that React uses a virtual DOM and only updates the real DOM when it needs to. But that makes me wonder when it does this. Looking at the DOM elements when I change a value on a square, I have no idea whether React is updating the entire DOM table that the game uses or just a single cell in the table. Would seem rather senseless to rebuild the entire table just because the data in one cell gets updated. Is there a way to actually tell what parts in the real DOM get updated?

Nikita Sivukhin

I'm not a professional React dev, but you ask an interesting question, so I try to set out my understanding of React internals.

React gives you an ability to write any javascript code in your render function and because of this, it is hard for React to notice what exactly changed in your DOM tree. That is maybe the main reason to develop the virtual DOM because it helps React to compare changes in memory and after this update DOM attributes that changed. Of course, there is plenty of options, that you can use to mitigate this specialty of React:

  1. You can avoid unnecessary re-renders if you carefully organize the state of your application and store it closer to its usage (it's obvious that if you store all your application state in the root component than any update of the state will cause the re-render of whole application)
  2. You can avoid unnecessary re-renders with the help of shouldComponentUpdate/React.PureComponent. But be aware, that these optimizations doesn't comes for free.
  3. For rendering large lists you can use specialized libraries like react-vritualized. They speed-up interaction with large lists with a bunch of techniques like rendering only visible part of the list and carefully updating DOM elements.

Let's take a look at the simple example of how React updates DOM tree:

class View extends React.Component {
    render() {
        return <div style={{padding: "10px"}}>
            <div>{this.props.value}</div>
        </div>
    }
}

class Application extends React.Component {
    constructor(props) {
        super(props);
        this.state = {
            a: 2,
            b: 3
        };
    }

    render() {
        const pad = {padding: "10px"};
        return (
            <div style={{width: "250px"}}>
                <div style={pad}><View value={this.state.a + this.state.b}/></div>
                <div style={pad}><View value={`A: ${this.state.a}`}/></div>
                <div style={pad}><View value={`B: ${this.state.b}`}/></div>
                <button onClick={() =>
                    this.setState({a: this.state.a + 1, b: this.state.b - 1})
                }>
                    Increase A / Decrease B
                </button>
            </div>
        );
    }
}

This example contains three labels and one button, that changes some values. You can notice, that the first label always renders constant value (5 in this example) that preserved across button clicks.

If you inspect re-renders with the help of React DevTools (there is an extension for Chrome; when you install it you need to go in the Chrome DevTools, choose Components tab and enable option Highlight updates when component render), you will see the following picture:

Highlighted re-renders of DOM

The reason because React re-render first label is because by default React.Component works in such a way, that it re-renders component when reference to the props parameter changed from previous render call. Notice that JSX syntax expands in the sequence of function calls like this (where second arguments are the props object):

<View value={this.state.a + this.state.b}/>
// became
React.createElement(View, { value: this.state.a + this.state.b })

[take a look at the articles about React internals without JSX and other stuff]

You can see that reference to props always updated and because of that React always needs to re-render element. But how can we avoid such a waste of time? We can fix this issue quite easily with the help of shouldComponentUpdate method (you can find an in-depth explanation of this method in official doc). In simple words, this method always called before every re-render and if it returns false than components stay unchanged. So, we can improve our View component in the following way:

class View extends React.Component {
    shouldComponentUpdate(nextProps, nextState, nextContext) {
        return nextProps.value !== this.props.value;
    }
    ...
}

And then only two labels re-renders after button clicks:

improve with shouldComponentUpdate

There is already an implemented class React.PureComponent that does exactly what we needed - it shallowly compares previous props with next props and prevents re-render in case of objects equality (but note, that PureComponent doesn't compare deep objects recursively).

In case of rendering large lists, you can avoid re-rendering of single elements with this trick, but there is still an issue with memory consumption for virtual DOM that always will be re-created after you top-level component render function call. Maybe you can avoid this with the help of some caching or storing components in the state directly, but I think it is simpler to use special libraries for this task.

To summarize, React is a great library, but it gives developers too much freedom to the developer, and because of this React can't optimize some things for you. There is a cool talk from Evan You (creator of Vue.js) that discuss the tradeoff between frameworks that restrict developer abilities and libraries, that gives the developers a full power of javascript.

この記事はインターネットから収集されたものであり、転載の際にはソースを示してください。

侵害の場合は、連絡してください[email protected]

編集
0

コメントを追加

0

関連記事

分類Dev

React hook that runs AFTER the DOM updates

分類Dev

How to append to dom in React?

分類Dev

react-chartjs-2 not updating graph when state updates

分類Dev

Under Linux, how can I tell the real power consumed by a usb device

分類Dev

How can I tell if my Cordova application is running on a simulator or real device?

分類Dev

How to tell if a model instance is new or not when using UUIDField as a Primary Key

分類Dev

How to tell what wake source is when Wake Source: Unknown

分類Dev

How to tell xfce (or an application) where to put the window when starting?

分類Dev

How to Use nested routes in react router dom

分類Dev

How generate dynamic DOM element in React

分類Dev

How to circumvent mutability when manipulating the DOM in JavaScript?

分類Dev

react router dom is not updating class component when url change

分類Dev

How to system-test real-time react multiplayer game?

分類Dev

(React Context Beginner) React Context doesn't stat when changing page using react-rooter-dom

分類Dev

How to know if there are updates available?

分類Dev

How to know if all the setState updates have been applied to the state in a React component?

分類Dev

Is Firebase Firestore real-time updates using Cloud functions possible?

分類Dev

Get real time updates from a Facebook page I do not own

分類Dev

React-Native fresh App immediately closes when launch on real devices

分類Dev

react-router-dom, how to skip back button

分類Dev

How do I tell when a request is a forward in preHandle using Spring MVC?

分類Dev

How can I tell when a Layout (and all its child Views) has fully finished inflating?

分類Dev

When dragging onto a table, how do you tell which row got dropped onto?

分類Dev

how to tell rsync to preserve time stamp on files when source tree has a mounted point

分類Dev

How can I tell when my file system was last fsck-ed at all?

分類Dev

How to serialize correctly? Ajax updates all instances of a django upvote button in a object forloop when pressed

分類Dev

How to execute code when ReactJS component has been applied to DOM

分類Dev

React PropTypes DOM element?

分類Dev

React PropTypes DOM element?

Related 関連記事

  1. 1

    React hook that runs AFTER the DOM updates

  2. 2

    How to append to dom in React?

  3. 3

    react-chartjs-2 not updating graph when state updates

  4. 4

    Under Linux, how can I tell the real power consumed by a usb device

  5. 5

    How can I tell if my Cordova application is running on a simulator or real device?

  6. 6

    How to tell if a model instance is new or not when using UUIDField as a Primary Key

  7. 7

    How to tell what wake source is when Wake Source: Unknown

  8. 8

    How to tell xfce (or an application) where to put the window when starting?

  9. 9

    How to Use nested routes in react router dom

  10. 10

    How generate dynamic DOM element in React

  11. 11

    How to circumvent mutability when manipulating the DOM in JavaScript?

  12. 12

    react router dom is not updating class component when url change

  13. 13

    How to system-test real-time react multiplayer game?

  14. 14

    (React Context Beginner) React Context doesn't stat when changing page using react-rooter-dom

  15. 15

    How to know if there are updates available?

  16. 16

    How to know if all the setState updates have been applied to the state in a React component?

  17. 17

    Is Firebase Firestore real-time updates using Cloud functions possible?

  18. 18

    Get real time updates from a Facebook page I do not own

  19. 19

    React-Native fresh App immediately closes when launch on real devices

  20. 20

    react-router-dom, how to skip back button

  21. 21

    How do I tell when a request is a forward in preHandle using Spring MVC?

  22. 22

    How can I tell when a Layout (and all its child Views) has fully finished inflating?

  23. 23

    When dragging onto a table, how do you tell which row got dropped onto?

  24. 24

    how to tell rsync to preserve time stamp on files when source tree has a mounted point

  25. 25

    How can I tell when my file system was last fsck-ed at all?

  26. 26

    How to serialize correctly? Ajax updates all instances of a django upvote button in a object forloop when pressed

  27. 27

    How to execute code when ReactJS component has been applied to DOM

  28. 28

    React PropTypes DOM element?

  29. 29

    React PropTypes DOM element?

ホットタグ

アーカイブ