Module 2.3: JSX & Rendering Logic

π― Learning Objectives
By the end of this module, youβll be able to:
- Grasp what JSX is and how it compiles into JavaScript.
- Differentiate between JSX and HTML (understanding
className,htmlFor, andcamelCase). - Leverage Fragments to group elements without adding extra nodes to the DOM.
- Embed JavaScript expressions using the
{}syntax. - Implement Conditional Rendering with
&&, ternary operators, and early returns. - Render lists efficiently using
.map()and understand the crucial role of the Key Prop.
1. What is JSX?
1.1. The Definition
JSX (JavaScript XML) is a syntax extension for JavaScript that lets you write HTML-like code directly within your JavaScript/TypeScript files.
// This is JSX
const element = <h1>Hello, React!</h1>;Think of JSX as more than just HTML or a template string; itβs essentially plain JavaScript after itβs been compiled.
1.2. How JSX Transforms
During the build process, tools like Babel or SWC transform your JSX into React.createElement() calls:

Before (JSX):
const element = (
<div className="container">
<h1>Hello</h1>
<p>Welcome to React</p>
</div>
);After Compilation (JavaScript):
const element = React.createElement(
'div',
{ className: 'container' },
React.createElement('h1', null, 'Hello'),
React.createElement('p', null, 'Welcome to React')
);π‘ Heads Up: Starting with React 17, the new JSX transform means you donβt need to
import Reactat the top of every file anymore. Build tools like Vite handle this configuration for you.
1.3. Why Embrace JSX?
| Advantage | Explanation |
|---|---|
| Intuitive | Writing UI feels more like HTML, making it easier to read than raw createElement() calls. |
| Type-safe | TypeScript provides robust checks for your props and elements. |
| Tooling | Enjoy excellent IDE support with autocompletion and syntax highlighting. |
| Compile-time | Catch errors early in the development cycle, during the build process. |
2. JSX Isnβt Quite HTML
2.1. Key Differences to Note

2.2. A Quick Comparison
HTML:
<label for="email" class="form-label">Email</label>
<input type="email" id="email" class="form-input" tabindex="1" onclick="handleClick()" style="color: red;" />JSX:
<label htmlFor="email" className="form-label">Email</label>
<input
type="email"
id="email"
className="form-input"
tabIndex={1}
onClick={handleClick}
style={{ color: 'red' }}
/>2.3. Self-Closing Tags
In JSX, all tags must be properly closed:
// β HTML style - This will cause errors in JSX
<img src="logo.png" />
<input type="text" />
<br />
// β
JSX - You must self-close them
<img src="logo.png" />
<input type="text" />
<br />2.4. Boolean Attributes
// HTML: The 'disabled' attribute doesn't need a value
<button disabled>Submit</button>
// JSX: You can write it like HTML or be explicit
<button disabled>Submit</button>
<button disabled={true}>Submit</button>
// Conditionally disable a button
<button disabled={isLoading}>Submit</button>3. Fragments
3.1. The Problem: JSX Must Return a Single Element
JSX requires you to return one root element:
// β Error: Adjacent JSX elements must be wrapped
function App() {
return (
<h1>Title</h1>
<p>Content</p>
);
}
// β
Wrap them in a single element
function App() {
return (
<div>
<h1>Title</h1>
<p>Content</p>
</div>
);
}The catch: Adding an unnecessary
<div>can bloat your DOM, potentially interfering with CSS layouts (like flexbox or grid).
3.2. The Solution: Fragments
Fragments allow you to group elements together without adding an extra node to the DOM:
// Method 1: The Fragment component
import { Fragment } from 'react'; // Import Fragment
function App() {
return (
<Fragment>
<h1>Title</h1>
<p>Content</p>
</Fragment>
);
}
// Method 2: Short syntax (highly recommended)
function App() {
return (
<>
<h1>Title</h1>
<p>Content</p>
</>
);
}3.3. Fragments with Keys
When rendering lists within a Fragment, youβll need to use the <Fragment> component and provide a key:
import { Fragment } from 'react';
function Glossary({ items }) {
return (
<dl>
{items.map((item) => (
<Fragment key={item.id}>
<dt>{item.term}</dt>
<dd>{item.description}</dd>
</Fragment>
))}
</dl>
);
}β οΈ The short syntax
<>...</>does not supportkey. You must use<Fragment key={...}>in this specific scenario.
4. Embedding Expressions
4.1. The {} Syntax
Use curly braces {} to embed JavaScript expressions directly into your JSX:
const name = 'React';
const version = 18;
function App() {
return (
<div>
<h1>Hello, {name}!</h1>
<p>Version: {version}</p>
<p>Sum: {1 + 1}</p>
<p>Uppercase: {name.toUpperCase()}</p>
<p>Current year: {new Date().getFullYear()}</p>
</div>
);
}4.2. Expressions vs. Statements
You can use these (Expressions - they return a value):
{name} // Variables
{1 + 1} // Math operations
{isActive ? 'Yes' : 'No'} // Ternary operators
{items.map(...)} // Method calls on arrays
{formatDate(date)} // Function callsYou cannot use these (Statements - they donβt return a value):
// β Errors - Statements are not allowed
if (condition) { ... }
for (let i = 0; ...) { ... }
const x = 54.3. Inline Styles
Styles in JSX are represented as JavaScript objects, not strings:
// β Incorrect - HTML style string
<div style="background-color: red; font-size: 16px">
// β
Correct - JSX style (object)
<div style={{ backgroundColor: 'red', fontSize: '16px' }}>
// β
Separated into its own object for clarity
const styles = {
backgroundColor: 'red',
fontSize: '16px',
padding: '1rem',
};
<div style={styles}>Content</div>π‘ Pro-Tip: CSS properties in JSX styles use camelCase (e.g.,
backgroundColorinstead ofbackground-color).
5. Conditional Rendering

5.1. The && (AND) Operator
Render an element only if the condition is true:
function Notification({ count }) {
return (
<div>
<h1>Messages</h1>
{count > 0 && <p>You have {count} unread messages.</p>}
</div>
);
}
// If count = 5 β Displays: "You have 5 unread messages."
// If count = 0 β Nothing is displayedβ οΈ Watch out for zero: Using
{count && <p>...</p>}will render the number0ifcountis 0. Use{count > 0 && ...}to prevent this.
5.2. The Ternary Operator
Render one of two options based on a condition:
function LoginButton({ isLoggedIn }) {
return <button>{isLoggedIn ? 'Logout' : 'Login'}</button>;
}
// If isLoggedIn = true β Displays: "Logout"
// If isLoggedIn = false β Displays: "Login"Render different components:
function Dashboard({ user }) {
return <div>{user ? <UserProfile user={user} /> : <LoginForm />}</div>;
}5.3. Early Return
Stop the rendering process early if a condition isnβt met:
function UserProfile({ user }) {
// Early return if no user is provided
if (!user) {
return <p>Please log in.</p>;
}
// This part only runs if a user object exists
return (
<div>
<h1>{user.name}</h1>
<p>{user.email}</p>
</div>
);
}5.4. When to Use What?
| Pattern | Best For |
|---|---|
&& | Show or hide an element. |
? : | Choose between two distinct options. |
| Early return | Complex logic with multiple conditions. |
6. Rendering Lists
6.1. Harnessing .map()
Use the Array.map() method to transform an array of data into a list of elements:
const fruits = ['Apple', 'Banana', 'Orange'];
function FruitList() {
return (
<ul>
{fruits.map((fruit) => (
<li>{fruit}</li>
))}
</ul>
);
}6.2. The key Prop - A Must-Have
Every item in a list must have a unique key prop:
const fruits = ['Apple', 'Banana', 'Orange'];
function FruitList() {
return (
<ul>
{fruits.map((fruit, index) => (
<li key={fruit}>{fruit}</li> // Using the fruit name as a key here
))}
</ul>
);
}
6.3. Why Do We Need Keys?
Keys are essential for React to identify which elements have changed, been added, or removed in a list:
// Without a key - React doesn't know which element is which
// β It might re-render the entire list (slow)
// With a key - React tracks each element by its key
// β It only updates the elements that have actually changed (fast)6.4. Why Using Index as a Key is Bad Practice
// β Bad practice - Using the index as a key
{
items.map((item, index) => <Item key={index} data={item} />);
}The Problem: If you add, delete, or reorder items in your list, the index will change. This misleads React into thinking itβs a completely different item:
| Before | After (adding item at the beginning) |
|---|---|
| key=0: Apple | key=0: Mango (incorrect!) |
| key=1: Banana | key=1: Apple (incorrect!) |
| key=2: Orange | key=2: Banana (incorrect!) |
| key=3: Orange |
The Consequences:
- State can get mixed up between items.
- Animations and transitions might not work as expected.
- Performance can suffer due to unnecessary re-renders.
6.5. The Right Way to Use Keys
// β
Good - Use a unique ID from your data
const users = [
{ id: 'u1', name: 'Alice' },
{ id: 'u2', name: 'Bob' },
];
function UserList() {
return (
<ul>
{users.map((user) => (
<li key={user.id}>{user.name}</li>
))}
</ul>
);
}Valid keys include:
- Database IDs (
user.id,product.sku) - Unique business identifiers (
email,uuid) - Generated IDs (if your data lacks inherent unique identifiers)
6.6. Rendering Lists of Objects
const products = [
{ id: 1, name: 'Laptop', price: 999 },
{ id: 2, name: 'Phone', price: 699 },
];
function ProductList() {
return (
<div className="product-grid">
{products.map((product) => (
<div key={product.id} className="product-card">
<h3>{product.name}</h3>
<p>${product.price}</p>
</div>
))}
</div>
);
}