Follow AiTechWorlds on LinkedIn for professional AI content!Follow Now →
18 minLesson 18 of 40
React Fundamentals

Lists, Keys & Conditional Rendering

Lists, Keys & Conditional Rendering

Rendering lists and conditionally showing elements are the most common patterns in React. Getting them right — especially the key prop — prevents subtle bugs and poor performance.

Rendering Lists

const fruits = ["Apple", "Banana", "Cherry"];

// Basic list
function FruitList() {
    return (
        <ul>
            {fruits.map((fruit, index) => (
                <li key={index}>{fruit}</li>
            ))}
        </ul>
    );
}

// Object lists
const users = [
    { id: 1, name: "Alice", role: "admin" },
    { id: 2, name: "Bob", role: "user" }
];

function UserList() {
    return (
        <ul>
            {users.map(user => (
                <UserCard key={user.id} user={user} />
            ))}
        </ul>
    );
}

The key Prop

Keys help React identify which items changed, added, or removed. Without keys, React has to re-render the entire list on any change:

// ❌ Index as key — buggy when items reorder or are deleted
{items.map((item, index) => <Item key={index} item={item} />)}

// ✅ Stable unique ID as key
{items.map(item => <Item key={item.id} item={item} />)}

// When you have no ID, use a stable unique value
{tags.map(tag => <Tag key={tag.name} tag={tag} />)}

When index keys cause bugs:

// If you have a list with input fields and delete item[1]:
// With index keys: item[2] gets key=1, React thinks it's the same as old item[1]
// React reuses the DOM node — the input value doesn't reset!
// With ID keys: React correctly removes the old element and creates a new one

Empty and Loading States

function ProductList({ products, loading, error }) {
    if (loading) {
        return <div className="spinner">Loading products...</div>;
    }
    
    if (error) {
        return <div className="error">Failed to load: {error.message}</div>;
    }
    
    if (products.length === 0) {
        return (
            <div className="empty">
                <p>No products found.</p>
                <button onClick={resetFilters}>Clear filters</button>
            </div>
        );
    }
    
    return (
        <div className="product-grid">
            {products.map(product => (
                <ProductCard key={product.id} product={product} />
            ))}
        </div>
    );
}

Conditional Rendering Patterns

function Dashboard({ user }) {
    // 1. Early return
    if (!user) return <Navigate to="/login" />;
    
    return (
        <div>
            {/* 2. && operator — renders right side when left is truthy */}
            {user.notifications > 0 && (
                <NotificationBadge count={user.notifications} />
            )}
            
            {/* 3. Ternary */}
            {user.isPremium ? <PremiumFeatures /> : <UpgradeBanner />}
            
            {/* 4. Nullish coalescing for defaults */}
            <p>{user.bio ?? "No bio provided."}</p>
            
            {/* 5. Switch via object map */}
            {{ free: <FreePlan />, pro: <ProPlan />, enterprise: <EnterprisePlan /> }[user.plan]}
        </div>
    );
}

Filtering and Transforming Lists

function FilteredProductList({ products, searchQuery, category }) {
    const filtered = products
        .filter(p => !category || p.category === category)
        .filter(p => p.name.toLowerCase().includes(searchQuery.toLowerCase()))
        .sort((a, b) => a.name.localeCompare(b.name));
    
    return (
        <div>
            <p>{filtered.length} products found</p>
            {filtered.length > 0 ? (
                <ul>
                    {filtered.map(p => (
                        <li key={p.id}>
                            <strong>{p.name}</strong> — ${p.price.toFixed(2)}
                        </li>
                    ))}
                </ul>
            ) : (
                <p className="empty">No products match your search.</p>
            )}
        </div>
    );
}

Fragments

When you need to return multiple elements without a wrapper div:

import { Fragment } from "react";

function TableRow({ user }) {
    // You can't return two <td>s without wrapping in <tr>
    // But the parent <tr> is already in the parent component
    return (
        <>
            <td>{user.name}</td>
            <td>{user.email}</td>
            <td>{user.role}</td>
        </>
    );
}

// Fragment with key (for lists)
function GlossaryList({ items }) {
    return (
        <dl>
            {items.map(item => (
                <Fragment key={item.id}>
                    <dt>{item.term}</dt>
                    <dd>{item.definition}</dd>
                </Fragment>
            ))}
        </dl>
    );
}

Next lesson: Forms in React — controlled components, validation, and submission.

📱

Get this course's notes on Telegram!

Free cheat sheets, summaries & practice exercises

Get Notes Free →
!