Fading Coder

One Final Commit for the Last Sprint

Home > Tech > Content

Virtual DOM, JSX, and Diff Algorithm in React for Writing More Efficient Code

Tech 1

When React component state updates, React does not destroy and re-render the entire component tree. Instead, it reuses existing DOM nodes wherever possible to minimize unnecessary DOM operations, which drastically improves performance.

The Virtual DOM is React's in-memory representation of the actual browser DOM. JSX is the syntax extension that lets you write HTML-like structure within JavaScript code, which React transpiles into descriptions of Virtual DOM nodes. When state changes, React generates an updated Virtual DOM tree, then uses the diff algorithm to compare it against the old Virtual DOM tree, calculates the minimum set of changes required, and only updates the changed portions of the real DOM.

React components are structured in a hierarchical tree layout. Finding the minimum set of edits between two arbitrary trees is a problem with a naive time complexity of O(n³), which is far too slow for practical frontend use cases with frequent updates. React's diff algorithm uses a simple but effective heuristic approach to bring the complexity down to nearly O(n). To use a practical analogy: instead of replacing your entire computer when only the keyboard breaks, you just replace the faulty keyboard.

React splits the comparison process by tree level, only matching nodes against other nodes at the same depth in the tree. This simplification barely impacts accuracy for real-world web apps, as components almost never move between different hierarchy levels, and most changes are reorderings among sibling nodes.

Hierarchical Comparison Example

import React, { Component } from 'react';

export default class DiffHierarchyDemo extends Component {
  constructor(props) {
    super(props);
    this.state = {
      showPrimaryContent: true
    };
  }

  handleToggle = (event) => {
    this.setState({
      showPrimaryContent: event.currentTarget.checked
    });
  };

  render() {
    return (
      <div>
        <h1>Diff Algorithm Demo</h1>
        <input 
          type="checkbox" 
          checked={this.state.showPrimaryContent} 
          onChange={this.handleToggle}
        />
        {this.state.showPrimaryContent ? (
          <p>Displayed when state is true</p>
        ) : (
          <p>Displayed when state is false</p>
        )}
      </div>
    );
  }
}

List Diffing with Keys Example

When renderinng dynamic lists, React relies on the key prop to correctly match existing DOM nodes to new list items, avoiding unnecessary re-creation of nodes and improving performance.

import React, { Component } from 'react';

export default class ListKeyDemo extends Component {
  constructor(props) {
    super(props);
    this.state = {
      items: ['aa', 'bb', 'cc', 'dd']
    };
  }

  shouldComponentUpdate() {
    return true;
  }

  appendItem = () => {
    const updatedItems = [...this.state.items, 'eee'];
    this.setState({ items: updatedItems });
  };

  prependItem = () => {
    const updatedItems = ['ff', ...this.state.items];
    this.setState({ items: updatedItems });
  };

  insertToCenter = () => {
    // Placeholder for insert logic
  };

  render() {
    return (
      <div>
        <button onClick={this.appendItem}>Add to end</button>
        <button onClick={this.prependItem}>Add to start</button>
        <button onClick={this.insertToCenter}>Add to middle</button>
        <ul>
          {this.state.items.map((item) => (
            <li key={item}>{item}</li>
          ))}
        </ul>
      </div>
    );
  }
}

Update Control Example

When implementing shouldComponentUpdate for manual performance tuning, you must return true to allow the component to update after state changes. Returning false will block all re-renders even when state changes.

import React, { Component } from 'react';

export default class UpdateControlDemo extends Component {
  constructor(props) {
    super(props);
    this.state = {
      items: ['aa', 'bb', 'cc', 'dd']
    };
  }

  shouldComponentUpdate() {
    // Uncomment below to block all re-renders
    // return false
    return true; // Allow updates when state changes
  }

  appendItem = () => {
    const newItems = this.state.items.slice();
    newItems.push('eee');
    this.setState({ items: newItems });
  };

  prependItem = () => {
    const newItems = ['ff', ...this.state.items];
    this.setState({ items: newItems });
  };

  insertToCenter = () => {};

  render() {
    return (
      <div>
        <button onClick={this.appendItem}>Append item</button>
        <button onClick={this.prependItem}>Prepend item</button>
        <button onClick={this.insertToCenter}>Insert to middle</button>
        <ul>
          {this.state.items.map((item) => (
            <li key={item}>{item}</li>
          ))}
        </ul>
      </div>
    );
  }
}

Related Articles

Understanding Strong and Weak References in Java

Strong References Strong reference are the most prevalent type of object referencing in Java. When an object has a strong reference pointing to it, the garbage collector will not reclaim its memory. F...

Comprehensive Guide to SSTI Explained with Payload Bypass Techniques

Introduction Server-Side Template Injection (SSTI) is a vulnerability in web applications where user input is improper handled within the template engine and executed on the server. This exploit can r...

Implement Image Upload Functionality for Django Integrated TinyMCE Editor

Django’s Admin panel is highly user-friendly, and pairing it with TinyMCE, an effective rich text editor, simplifies content management significantly. Combining the two is particular useful for bloggi...

Leave a Comment

Anonymous

◎Feel free to join the discussion and share your thoughts.