Skip to content

React Element Rendering

Overview

React elements are the smallest units that make up a React application. This chapter will deeply understand React element creation, rendering mechanism, how the Virtual DOM works, and how to efficiently update the user interface.

🧩 What is a React Element

React Element Basics

jsx
// React element is an object describing what you want to see on screen
const element = <h1>Hello, World!</h1>;

// Equivalent (using React.createElement)
const element = React.createElement(
  'h1',           // Tag name
  null,           // Props
  'Hello, World!' // Children
);

// React elements are immutable objects
console.log(element);
// Output:
// {
//   type: 'h1',
//   props: {
//     children: 'Hello, World!'
//   },
//   key: null,
//   ref: null,
//   ...
// }

Elements vs Components

jsx
// React element - object describing a DOM node
const divElement = <div>This is an element</div>;

// React component - function or class that returns an element
function Welcome() {
  return <h1>This is a component</h1>;
}

// Component element - object describing a component instance
const componentElement = <Welcome />;

🎨 Creating React Elements

JSX Element Creation

jsx
// Simple elements
const heading = <h1>Title</h1>;
const paragraph = <p>This is a paragraph</p>;

// Elements with attributes
const link = <a href="https://react.dev" target="_blank">React Official Site</a>;
const image = <img src="/logo.png" alt="Logo" width="100" />;

// Elements with styles
const styledDiv = (
  <div
    style={{
      backgroundColor: 'blue',
      color: 'white',
      padding: '20px'
    }}
  >
    Styled div
  </div>
);

// Complex element structure
const card = (
  <div className="card">
    <img src="/avatar.jpg" alt="Avatar" className="card-image" />
    <div className="card-content">
      <h3 className="card-title">Username</h3>
      <p className="card-description">This is user description</p>
      <button className="card-button">View Details</button>
    </div>
  </div>
);

React.createElement Element Creation

jsx
// Using React.createElement to create elements
const elementWithoutJSX = React.createElement(
  'div',                          // Element type
  { className: 'container' },     // Props object
  React.createElement(            // Children
    'h1',
    { style: { color: 'red' } },
    'Title'
  ),
  React.createElement(
    'p',
    null,
    'This is a paragraph'
  )
);

// Equivalent JSX
const elementWithJSX = (
  <div className="container">
    <h1 style={{ color: 'red' }}>Title</h1>
    <p>This is a paragraph</p>
  </div>
);

🚀 Rendering Elements to DOM

Basic Rendering

jsx
import React from 'react';
import ReactDOM from 'react-dom/client';

// Create element
const element = <h1>Hello, React!</h1>;

// Get DOM container
const container = document.getElementById('root');

// Create React root
const root = ReactDOM.createRoot(container);

// Render element
root.render(element);

Rendering Complex Elements

jsx
function App() {
  const user = {
    name: 'John',
    email: 'john@example.com',
    avatar: '/avatars/john.jpg'
  };

  const element = (
    <div className="app">
      <header className="app-header">
        <h1>Welcome to Our App</h1>
        <nav>
          <a href="/home">Home</a>
          <a href="/about">About</a>
          <a href="/contact">Contact</a>
        </nav>
      </header>

      <main className="app-main">
        <div className="user-profile">
          <img src={user.avatar} alt={user.name} />
          <h2>{user.name}</h2>
          <p>{user.email}</p>
        </div>

        <section className="content">
          <h3>Main Content</h3>
          <p>This is the main content area of the application.</p>
        </section>
      </main>

      <footer className="app-footer">
        <p>&copy; 2024 My App. All rights reserved.</p>
      </footer>
    </div>
  );

  return element;
}

const root = ReactDOM.createRoot(document.getElementById('root'));
root.render(<App />);

🔄 Updating Rendered Elements

Element Immutability

jsx
// React elements are immutable
const element1 = <h1>First Render</h1>;
const element2 = <h1>Second Render</h1>;

// Cannot modify created elements
// element1.props.children = 'Modified content'; // This is wrong!

// To update UI, need to create new elements and re-render
const root = ReactDOM.createRoot(document.getElementById('root'));

// First render
root.render(element1);

// Update render (create new element)
setTimeout(() => {
  root.render(element2);
}, 2000);

Real-time Update Example

jsx
function Clock() {
  const [time, setTime] = React.useState(new Date());

  // Update time every second
  React.useEffect(() => {
    const timer = setInterval(() => {
      setTime(new Date());
    }, 1000);

    // Cleanup timer
    return () => clearInterval(timer);
  }, []);

  // Each state update creates new elements
  return (
    <div className="clock">
      <h2>Current Time</h2>
      <div className="time-display">
        {time.toLocaleTimeString()}
      </div>
      <div className="date-display">
        {time.toLocaleDateString()}
      </div>
    </div>
  );
}

function App() {
  return (
    <div>
      <h1>Real-time Clock App</h1>
      <Clock />
    </div>
  );
}

🌳 Virtual DOM Concept

How Virtual DOM Works

jsx
// Virtual DOM is the JavaScript representation of React elements
const virtualDOM = {
  type: 'div',
  props: {
    className: 'container',
    children: [
      {
        type: 'h1',
        props: {
          children: 'Title'
        }
      },
      {
        type: 'p',
        props: {
          children: 'Paragraph content'
        }
      }
    ]
  }
};

// React uses Virtual DOM to compute minimal updates
function VirtualDOMExample() {
  const [showDetails, setShowDetails] = React.useState(false);

  return (
    <div className="container">
      <h1>User Info</h1>
      <button onClick={() => setShowDetails(!showDetails)}>
        {showDetails ? 'Hide' : 'Show'} Details
      </button>
      {showDetails && (
        <div className="details">
          <p>Name: John</p>
          <p>Age: 25</p>
          <p>Occupation: Developer</p>
        </div>
      )}
    </div>
  );
}

// React only updates the changed parts, not re-rendering the entire component

Diff Algorithm Demo

jsx
function DiffExample() {
  const [items, setItems] = React.useState([
    { id: 1, name: 'Apple' },
    { id: 2, name: 'Banana' },
    { id: 3, name: 'Orange' }
  ]);

  const addItem = () => {
    const newItem = {
      id: Date.now(),
      name: `New Fruit ${items.length + 1}`
    };
    setItems([...items, newItem]);
  };

  const removeItem = (id) => {
    setItems(items.filter(item => item.id !== id));
  };

  return (
    <div>
      <h2>Fruit List</h2>
      <button onClick={addItem}>Add Fruit</button>

      <ul>
        {items.map(item => (
          <li key={item.id}>
            {item.name}
            <button onClick={() => removeItem(item.id)}>
              Delete
            </button>
          </li>
        ))}
      </ul>

      <p>Total: {items.length}</p>
    </div>
  );
}

// React uses the key attribute to identify which elements have changed
// This allows more efficient DOM updates

🎯 Conditional Element Rendering

Basic Conditional Rendering

jsx
function ConditionalRendering() {
  const [isLoggedIn, setIsLoggedIn] = React.useState(false);
  const [userRole, setUserRole] = React.useState('guest');

  // Conditionally render different elements
  let welcomeElement;
  if (isLoggedIn) {
    welcomeElement = <h1>Welcome back!</h1>;
  } else {
    welcomeElement = <h1>Please log in first</h1>;
  }

  return (
    <div>
      {welcomeElement}

      {/* Using ternary operator */}
      {isLoggedIn ? (
        <div className="user-dashboard">
          <p>You have successfully logged in</p>
          <button onClick={() => setIsLoggedIn(false)}>
            Logout
          </button>
        </div>
      ) : (
        <div className="login-form">
          <p>Please log in to continue</p>
          <button onClick={() => setIsLoggedIn(true)}>
            Login
          </button>
        </div>
      )}

      {/* Using logical AND operator */}
      {isLoggedIn && userRole === 'admin' && (
        <div className="admin-panel">
          <h3>Admin Panel</h3>
          <button>Manage Users</button>
          <button>System Settings</button>
        </div>
      )}

      {/* Complex conditional rendering */}
      {(() => {
        switch (userRole) {
          case 'admin':
            return <div>Admin Interface</div>;
          case 'user':
            return <div>User Interface</div>;
          case 'guest':
          default:
            return <div>Guest Interface</div>;
        }
      })()}
    </div>
  );
}

Null Handling

jsx
function NullHandling() {
  const [data, setData] = React.useState(null);
  const [loading, setLoading] = React.useState(true);
  const [error, setError] = React.useState(null);

  React.useEffect(() => {
    // Simulate data fetching
    setTimeout(() => {
      try {
        // Random success or failure
        if (Math.random() > 0.5) {
          setData({ message: 'Data loaded successfully!' });
        } else {
          throw new Error('Data loading failed');
        }
      } catch (err) {
        setError(err.message);
      } finally {
        setLoading(false);
      }
    }, 2000);
  }, []);

  // Return different elements for different states
  if (loading) {
    return (
      <div className="loading">
        <p>Loading...</p>
      </div>
    );
  }

  if (error) {
    return (
      <div className="error">
        <p>Error: {error}</p>
        <button onClick={() => window.location.reload()}>
          Retry
        </button>
      </div>
    );
  }

  if (!data) {
    return (
      <div className="no-data">
        <p>No data available</p>
      </div>
    );
  }

  return (
    <div className="success">
      <p>{data.message}</p>
    </div>
  );
}

📋 List Element Rendering

Basic List Rendering

jsx
function ListRendering() {
  const fruits = ['Apple', 'Banana', 'Orange', 'Grape', 'Strawberry'];

  const users = [
    { id: 1, name: 'John', email: 'john@example.com' },
    { id: 2, name: 'Jane', email: 'jane@example.com' },
    { id: 3, name: 'Bob', email: 'bob@example.com' }
  ];

  return (
    <div>
      {/* Simple list */}
      <h2>Fruit List</h2>
      <ul>
        {fruits.map((fruit, index) => (
          <li key={index}>{fruit}</li>
        ))}
      </ul>

      {/* Complex list */}
      <h2>User List</h2>
      <div className="user-list">
        {users.map(user => (
          <div key={user.id} className="user-card">
            <h3>{user.name}</h3>
            <p>{user.email}</p>
            <button>View Details</button>
          </div>
        ))}
      </div>
    </div>
  );
}

Importance of Key Attribute

jsx
function KeyImportance() {
  const [items, setItems] = React.useState([
    { id: 1, name: 'Item 1', count: 0 },
    { id: 2, name: 'Item 2', count: 0 },
    { id: 3, name: 'Item 3', count: 0 }
  ]);

  const addItem = () => {
    const newItem = {
      id: Date.now(),
      name: `Item ${items.length + 1}`,
      count: 0
    };
    setItems([newItem, ...items]); // Add at beginning
  };

  const updateCount = (id, newCount) => {
    setItems(items.map(item =>
      item.id === id ? { ...item, count: newCount } : item
    ));
  };

  return (
    <div>
      <h2>Key Attribute Demo</h2>
      <button onClick={addItem}>Add Item at Beginning</button>

      <div className="items-container">
        {items.map(item => (
          <div key={item.id} className="item">
            <h3>{item.name}</h3>
            <div>
              <span>Count: {item.count}</span>
              <button onClick={() => updateCount(item.id, item.count + 1)}>
                +1
              </button>
              <button onClick={() => updateCount(item.id, item.count - 1)}>
                -1
              </button>
            </div>
          </div>
        ))}
      </div>

      {/* Bad example: using index as key */}
      <h3>Bad Example (Don't do this):</h3>
      <div className="bad-example">
        {items.map((item, index) => (
          <div key={index} className="item">
            {/* Using index as key can cause rendering issues */}
            <span>{item.name}</span>
          </div>
        ))}
      </div>
    </div>
  );
}

⚡ Performance Optimization

React.memo for Rendering Optimization

jsx
// Child component to be optimized
const ExpensiveComponent = React.memo(function ExpensiveComponent({ value, onUpdate }) {
  console.log('ExpensiveComponent rendered', value);

  // Simulate expensive computation
  const expensiveValue = React.useMemo(() => {
    console.log('Running expensive computation');
    let result = 0;
    for (let i = 0; i < 1000000; i++) {
      result += Math.random();
    }
    return result;
  }, [value]);

  return (
    <div className="expensive-component">
      <h3>Expensive Component</h3>
      <p>Value: {value}</p>
      <p>Computed result: {expensiveValue.toFixed(2)}</p>
      <button onClick={() => onUpdate(value + 1)}>
        Update Value
      </button>
    </div>
  );
});

function PerformanceExample() {
  const [count, setCount] = React.useState(0);
  const [otherState, setOtherState] = React.useState(0);

  // Use useCallback to optimize callback functions
  const handleUpdate = React.useCallback((newValue) => {
    setCount(newValue);
  }, []);

  return (
    <div>
      <h2>Performance Optimization Example</h2>
      <div>
        <p>Count: {count}</p>
        <p>Other state: {otherState}</p>

        <button onClick={() => setCount(count + 1)}>
          Increment Count
        </button>
        <button onClick={() => setOtherState(otherState + 1)}>
          Increment Other State
        </button>
      </div>

      {/* Only re-renders when count changes */}
      <ExpensiveComponent
        value={count}
        onUpdate={handleUpdate}
      />
    </div>
  );
}

Lazy Loading Elements

jsx
const LazyComponent = React.lazy(() => import('./LazyComponent'));

function LazyRenderingExample() {
  const [showLazy, setShowLazy] = React.useState(false);

  return (
    <div>
      <h2>Lazy Loading Example</h2>
      <button onClick={() => setShowLazy(!showLazy)}>
        {showLazy ? 'Hide' : 'Show'} Lazy Component
      </button>

      {showLazy && (
        <React.Suspense fallback={<div>Loading...</div>}>
          <LazyComponent />
        </React.Suspense>
      )}
    </div>
  );
}

📝 Chapter Summary

Through this chapter, you should have mastered:

Core Concepts

  • ✅ The nature and characteristics of React elements
  • ✅ How Virtual DOM works
  • ✅ Element creation and rendering mechanism
  • ✅ Element update immutability

Rendering Techniques

  • ✅ Multiple ways of conditional rendering
  • ✅ List rendering and Key attribute
  • ✅ Null and error state handling
  • ✅ Performance optimization strategies

Best Practices

  1. Use correct keys: Ensure list rendering performance
  2. Reasonable conditional rendering: Avoid unnecessary element creation
  3. Performance optimization: Use memo and useMemo
  4. Error boundaries: Handle rendering errors
  5. Lazy loading: Load components on demand

Important Principles

  • React elements are immutable
  • Each update creates a new element tree
  • React uses Diff algorithm to optimize updates
  • Key attribute helps React identify element changes

Continue Learning: Next Chapter - React Event Handling

Content is for learning and research only.