Rendering in React

Nitish JhaNitish Jha
4 min read

What is rendering in react ?

React rendering is the process of converting react elements into UI elements that can be displayed on screen .

The react elements are simple javascript object which contains the structure which we want to display / render.

const element = <h1>Hello, React!</h1>;
const reactElement = {
  $$typeof: Symbol('react.element'),
  type: 'div',
  key: null,
  ref: null,
  props: {
    children: 'Hello, React!'
  },
  _owner: null,
  _store: {}
}
  • Key Details

    • $$typeof: Identifies it as a React element

    • key: Used for list rendering

    • ref: Reference to a DOM element or component

    • _owner: Internal React property tracking component hierarchy

    • _store: Internal optimization object

These JavaScript objects are obtained from react elements using React.createElement() function calls by transpilers like Babel, therefore this abstraction layer provides a declarative way to describe UI and separates description and rendering logic unlike direct dom manipulation.

// Equivalent React.createElement() call
const element = React.createElement('h1', null, 'Hello, React!');

React elements are immutable objects and each update creates new react element (js object tree using diffing algo) for easy comparison.

// Initial element
let counter = {
  type: 'div',
  props: {
    children: 'Count: 0'
  }
};

// New element (creating a new object, not modifying)
counter = {
  type: 'div',
  props: {
    children: 'Count: 1'
  }
};

Whenever any event triggers, react collects all the state updates, batches together and creates new virtual DOM Tree, unlike immediate rendering by DOM.

// Inefficient 
function updateUI() {
  // Each update triggers immediate DOM manipulation
  document.getElementById('count').textContent = newCount;
  document.getElementById('status').className = newStatus;
}
function Counter() {
  const [count, setCount] = useState(0);
  const [clicked, setClicked] = useState(false);

  const handleClick = () => {
    // Multiple state updates in a single event handler
    setCount(c => c + 1);   // Update 1
    setClicked(true);       // Update 2
    // React will batch these updates together
  };

  return (
    <div>
      <p>Count: {count}</p>
      <button onClick={handleClick}>Increment</button>
    </div>
  );
}

Therefore, react Elements are more efficient because there is no immediate rendering, it collects multiple state updates on an event and process together instead multiple immediate DOM manipulation for the same event and it only updates what has changed by comparing previous virtual DOM tree with new Virtual DOM, it's able to do because react elements are immutable objects and each update creates new react element

Therefore when state changes new virtual Dom tree ,compares with the previous virtual dom tree, calculate minimal change and efficiently updates real Dom. This is called react's reconciliation process.

Virtual DOM is a Tree-like structure of React elements. It's essentially a JavaScript object that mirrors the structure of the real DOM, but is much faster to manipulate.

HTML vs DOM vs Virtual DOM Object

HTML Representation

//css
 <style>
        #user-profile {
            background-color: blue;
            color: white;
            padding: 10px;
        }
    </style>

//   html
    <div 
        id="user-profile" 
        class="profile active" 
        data-user-id="123"
    >
        <h2>John Doe</h2>
    </div>

//Javscript
    <script>

        const divElement = document.getElementById('user-profile');
        divElement.addEventListener('click', () => {
            console.log('Div clicked');
        });

        console.log(divElement.offsetWidth);  // Rendered width
        console.log(divElement.clientHeight); // Inner height
    </script>

Abstract Representation of a DOM element object contains basically these 5 properties -

{
  nodeType: 1,            // Always exists for elements
  tagName: 'ELEMENT_TAG', // Tag name of the element (e.g., 'DIV', 'H1')
  attributes: NamedNodeMap {}, // Attribute collection (empty if no attributes)
  childNodes: NodeList [],     // List of children (empty if no children)
  parentNode: Element || null  // Parent node (null for <html>)
}
{

  nodeType: 1,  // Element node type
  tagName: 'DIV',
  nodeName: 'DIV',

  // Identification Properties
  id: 'user-profile',
  className: 'profile active',

  // Attributes Collection
  attributes: NamedNodeMap {
    'id': {
      name: 'id',
      value: 'user-profile'
    },
    'class': {
      name: 'class',
      value: 'profile active'
    },
    'data-user-id': {
      name: 'data-user-id',
      value: '123'
    }
  },

  // Custom Data Attributes
  dataset: {
    userId: '123'
  },

  // Style Properties
  style: CSSStyleDeclaration {
    backgroundColor: 'blue',
    color: 'white',
    padding: '10px',
    // Many other inherited CSS properties
  },

  // Event Listeners
  _listeners: {
    click: [
      {
        type: 'click',
        listener: () => {
          console.log('Div clicked')
        },
        capture: false
      }
    ]
  },

  // Child Node Relationship
  childNodes: [
    {
      nodeType: 1,
      tagName: 'H2',
      textContent: 'John Doe',
      // Additional H2 element properties
    }
  ],

  // Parent-Child Methods
  appendChild: [Function],
  removeChild: [Function],
  insertBefore: [Function],

  // Dimensional Properties
  offsetWidth: 0,  // Will be calculated when rendered
  offsetHeight: 0,
  clientWidth: 0,
  clientHeight: 0,

  // Positioning Properties
  offsetTop: 0,
  offsetLeft: 0,

  // Traversal Methods
  querySelector: [Function],
  querySelectorAll: [Function],

  // Event Methods
  addEventListener: [Function],
  removeEventListener: [Function],

  // Inheritance
  __proto__: HTMLDivElement.prototype
}

React Element JS Object

// React equivalent (Lightweight)
{
  type: 'div',
  props: {
    id: 'user-profile',
    className: 'profile active',
    style: {
      backgroundColor: 'blue',
      color: 'white',
      padding: '10px'
    },
    'data-user-id': '123',
    children: [
      {
        type: 'h2',
        props: {
          children: 'John Doe'
        }
      }
    ]
  }
}

Hence,

  • Abstraction layer which provides declarative way to describe UI and separates rendering logic using React.createElement()

  • the immutability of react element objects for comparision and optimization,

  • and light weight object representation makes React rendering more efficient.

There are ways in which rendering can be made more efficient using Memoization, LazyLoading and code splitting. We will discuss this in next post.

0
Subscribe to my newsletter

Read articles from Nitish Jha directly inside your inbox. Subscribe to the newsletter, and don't miss out.

Written by

Nitish Jha
Nitish Jha