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>© 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 componentDiff 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
- Use correct keys: Ensure list rendering performance
- Reasonable conditional rendering: Avoid unnecessary element creation
- Performance optimization: Use memo and useMemo
- Error boundaries: Handle rendering errors
- 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