React Tutorial 0/120 lessons ~6 min read Lesson 13

    Rendering UI

    Rendering UI explains React's initial render, createRoot, re-rendering from state and props, render and commit phases, reconciliation, purity, Strict Mode, identity, accessibility, and performance.

    Course progress0%
    Focus
    73 guided sections
    Practice signal
    Examples included
    Career prep
    Interview Q&A included

    Learning Objectives

    By the end of this lesson, you will be able to:

    1. Understand what rendering means in React.
    2. Understand the relationship between components, JSX, and rendering.
    3. Understand the React rendering lifecycle.
    4. Understand the initial render.
    5. Understand re-rendering.
    6. Understand how state changes trigger rendering.
    7. Understand how props can trigger rendering.
    8. Understand the role of createRoot().
    9. Understand React's render and commit phases.
    10. Understand reconciliation at a high level.
    11. Understand why rendering does not mean direct DOM replacement.
    12. Understand conditional rendering.
    13. Understand list rendering.
    14. Understand nested component rendering.
    15. Understand render purity.
    16. Understand Strict Mode's development behavior.
    17. Debug rendering problems using React Developer Tools.
    18. Understand common rendering performance issues.
    19. Explain React rendering confidently in senior-level interviews.

    Introduction

    We've already learned:

    text
    React
    ↓
    Vite
    ↓
    Project Structure
    ↓
    SPA
    ↓
    React Developer Tools
    ↓
    JSX

    Now we need to understand what actually happens after we write JSX.

    Consider:

    tsx
    function App() {
    return (
    <h1>Hello React</h1>
    );
    }

    We know that JSX describes the UI.

    But the important question is:

    How does that JSX become something visible in the browser?

    The high-level flow is:

    text
    Component
    ↓
    JSX
    ↓
    React Elements
    ↓
    Render
    ↓
    Reconciliation
    ↓
    Commit
    ↓
    DOM
    ↓
    Browser

    Understanding this flow is fundamental to becoming a strong React developer.

    What Does "Rendering" Mean in React?

    In React, rendering means React calls your components to determine what the UI should look like for the current props and state.

    For example:

    tsx
    function Welcome() {
    return <h1>Welcome</h1>;
    }

    When React renders Welcome, it evaluates the component and obtains the UI description:

    text
    Welcome
    ↓
    <h1>Welcome</h1>

    A useful mental model is:

    text
    Props + State
    ↓
    Component
    ↓
    JSX
    ↓
    React Element Tree

    Rendering is primarily about figuring out the next UI, not directly manipulating the DOM.

    Rendering Does Not Mean "Update the DOM"

    This is one of the most important concepts in React.

    Beginners often think:

    text
    Render
    =
    Change DOM

    That's not accurate.

    A better model is:

    text
    Render
    ↓
    Calculate desired UI
    ↓
    Compare with previous result
    ↓
    Commit required changes
    ↓
    DOM

    So:

    Rendering determines what the UI should be. The commit phase applies necessary changes to the DOM.

    The Initial Render

    When your React application starts, React performs an initial render.

    A typical Vite application contains something similar to:

    tsx
    import { StrictMode } from "react";
    import { createRoot } from "react-dom/client";
    import App from "./App";
    createRoot(
    document.getElementById("root")!
    ).render(
    <StrictMode>
    <App />
    </StrictMode>
    );

    Let's understand this step by step.

    The Root DOM Element

    Your HTML might contain:

    html
    <body>
    <div id="root"></div>
    </body>

    This element provides the location where React will manage the application UI.

    Think of it as:

    text
    Browser DOM
    │
    └── #root
    │
    ▼
    React App

    React doesn't need to manage the entire HTML document.

    It can manage a particular root.

    createRoot()

    Modern React uses:

    tsx
    import { createRoot } from "react-dom/client";

    Then:

    tsx
    const rootElement =
    document.getElementById("root");
    const root = createRoot(rootElement!);

    And finally:

    tsx
    root.render(<App />);

    Conceptually:

    text
    DOM element
    ↓
    createRoot()
    ↓
    React Root
    ↓
    render(<App />)

    The root establishes the connection between React and the DOM container.

    Rendering the App

    When we write:

    tsx
    root.render(<App />);

    we are telling React:

    Render this React element tree into this root.

    Conceptually:

    text
    <App />
    ↓
    App component
    ↓
    JSX
    ↓
    React element tree
    ↓
    DOM

    For example:

    tsx
    function App() {
    return (
    <main>
    <h1>TechLearningPro</h1>
    <p>Learn modern engineering.</p>
    </main>
    );
    }

    React determines the corresponding UI.

    Component Tree

    Suppose:

    tsx
    function App() {
    return (
    <Layout>
    <Header />
    <Main />
    <Footer />
    </Layout>
    );
    }

    React can conceptually form:

    text
    App
    └── Layout
    ├── Header
    ├── Main
    └── Footer

    During rendering, React evaluates the components and builds the corresponding element structure.

    React Element Tree

    Consider:

    tsx
    <h1>Hello React</h1>

    This JSX is transformed into a JavaScript representation of the element.

    Conceptually:

    text
    React Element
    {
    type: "h1",
    props: {
    children: "Hello React"
    }
    }

    The exact internal representation is more complex, but this mental model is useful.

    React uses this representation to determine what the UI should look like.

    Rendering a Component

    Consider:

    tsx
    function Greeting() {
    return <h1>Hello React</h1>;
    }

    When React renders it:

    text
    React
    ↓
    Call Greeting()
    ↓
    <h1>Hello React</h1>
    ↓
    React element

    The important point:

    React components are functions that React invokes during rendering.

    Components Are Not Called Like Normal UI Code

    You usually don't write:

    tsx
    const result = Greeting();

    Instead:

    tsx
    <Greeting />

    React controls when the component is evaluated.

    This allows React to manage:

    text
    Rendering
    State
    Updates
    Effects
    Context
    Scheduling

    Initial Rendering Example

    Consider:

    tsx
    function App() {
    return (
    <div>
    <h1>React Course</h1>
    <p>Learn rendering.</p>
    </div>
    );
    }

    The conceptual flow is:

    text
    root.render(<App />)
    ↓
    App()
    ↓
    JSX
    ↓
    React Elements
    ↓
    Reconciliation
    ↓
    Commit
    ↓
    DOM

    The browser then displays:

    text
    React Course
    Learn rendering.

    Re-rendering

    Initial rendering isn't the end.

    React applications are dynamic.

    Suppose:

    tsx
    function Counter() {
    const [count, setCount] = useState(0);
    return (
    <button
    onClick={() => setCount(count + 1)}
    >
    Count: {count}
    </button>
    );
    }

    Initial state:

    text
    count = 0

    The UI is:

    text
    Count: 0

    The user clicks.

    text
    setCount(1)

    React schedules an update.

    Then:

    text
    State change
    ↓
    Component re-render
    ↓
    New JSX result
    ↓
    Reconciliation
    ↓
    Commit necessary changes

    The UI becomes:

    text
    Count: 1

    What Causes a Re-render?

    Common causes include:

    text
    State update
    Props change
    Context update
    Parent re-render
    External store update

    For example:

    tsx
    setCount(count + 1);

    can cause the component to render again.

    State Change Flow

    The fundamental React loop is:

    text
    User Action
    ↓
    Event Handler
    ↓
    State Update
    ↓
    React schedules update
    ↓
    Component renders again
    ↓
    New UI description
    ↓
    Reconciliation
    ↓
    DOM update

    This is one of the most important diagrams in React.

    Rendering With Props

    Props can also affect rendering.

    Consider:

    tsx
    function CourseCard({
    title
    }: {
    title: string;
    }) {
    return <h2>{title}</h2>;
    }

    Parent:

    tsx
    <CourseCard title="React" />

    Later:

    tsx
    <CourseCard title="Angular" />

    The child needs to render based on the new prop value.

    Conceptually:

    text
    Parent
    ↓
    Props change
    ↓
    CourseCard
    ↓
    New JSX
    ↓
    Updated UI

    Parent Re-render

    A common misconception is:

    If a child has the same props, it can never render again.

    Not necessarily.

    If a parent renders:

    tsx
    function Parent() {
    const [count, setCount] = useState(0);
    return (
    <>
    <button onClick={() => setCount(count + 1)}>
    {count}
    </button>
    <Child />
    </>
    );
    }

    the parent renders again when count changes.

    By default, React may also evaluate the child as part of rendering that subtree.

    Later we'll study optimization techniques such as:

    text
    React.memo
    useMemo
    useCallback

    But first, understand the default rendering model.

    Re-render Does Not Mean Everything Changes

    Suppose:

    text
    Previous UI:
    <h1>React</h1>
    New UI:
    <h1>React</h1>

    React can determine that there is no meaningful DOM change.

    Therefore:

    text
    Component rendered
    ↓
    Same output
    ↓
    No DOM update required

    This is why:

    A render does not necessarily produce a DOM mutation.

    Render Phase

    React's rendering process can be conceptually divided into phases.

    The first is the:

    Render phase

    During this phase, React determines what the next UI should look like.

    Conceptually:

    text
    State / Props
    ↓
    Render phase
    ↓
    New React element tree

    The render phase should be treated as pure.

    Commit Phase

    After React determines the necessary changes, it enters the:

    Commit phase

    This is where React applies necessary changes to the host environment, such as the browser DOM.

    Conceptually:

    text
    Render phase
    ↓
    Determine changes
    ↓
    Commit phase
    ↓
    DOM updates

    Render vs Commit

    Remember this distinction:

    PhaseMain Responsibility
    RenderDetermine what UI should look like
    CommitApply necessary changes

    So:

    text
    Render ≠ DOM update

    Instead:

    text
    Render
    +
    Commit
    =
    Updated UI

    This distinction becomes extremely important when debugging performance.

    Why Render Must Be Pure

    React may render components more than once.

    Therefore, rendering code should not perform side effects.

    Bad:

    tsx
    function CoursePage() {
    localStorage.setItem(
    "visited",
    "true"
    );
    return <h1>Courses</h1>;
    }

    The problem is that writing to localStorage is a side effect.

    Better:

    tsx
    function CoursePage() {
    useEffect(() => {
    localStorage.setItem(
    "visited",
    "true"
    );
    }, []);
    return <h1>Courses</h1>;
    }

    Effects are a separate concept we'll study deeply later.

    What Is a Side Effect?

    A side effect is work that interacts with something outside the component's pure calculation.

    Examples:

    text
    API request
    localStorage write
    DOM manipulation
    Subscription
    Timer
    Analytics event

    Don't perform such operations directly during rendering.

    Instead, React provides mechanisms such as:

    text
    useEffect
    event handlers
    external APIs

    depending on the requirement.

    Rendering Should Be Deterministic

    Ideally:

    text
    Same props
    +
    Same state
    =
    Same UI result

    For example:

    tsx
    function Greeting({
    name
    }: {
    name: string;
    }) {
    return <h1>Hello {name}</h1>;
    }

    If:

    text
    name = "Jagannath"

    the component should consistently produce:

    text
    Hello Jagannath

    This predictability is a major advantage of React's declarative model.

    Conditional Rendering

    Rendering can depend on state.

    tsx
    function Dashboard({
    isLoggedIn
    }: {
    isLoggedIn: boolean;
    }) {
    return (
    <main>
    {isLoggedIn
    ? <UserDashboard />
    : <Login />}
    </main>
    );
    }

    Conceptually:

    text
    isLoggedIn
    │
    ├── true → UserDashboard
    │
    └── false → Login

    React renders the UI corresponding to the current state.

    Rendering Lists

    React commonly renders arrays into UI.

    tsx
    const courses = [
    { id: 1, title: "React" },
    { id: 2, title: "Java" },
    { id: 3, title: "Spring Boot" }
    ];

    Then:

    tsx
    <ul>
    {courses.map(course => (
    <li key={course.id}>
    {course.title}
    </li>
    ))}
    </ul>

    The rendering flow is:

    text
    Array
    ↓
    map()
    ↓
    React elements
    ↓
    List UI

    Why Keys Matter During Rendering

    Consider:

    text
    Before:
    A
    B
    C
    After:
    A
    C
    D

    React needs to understand the identity of each item.

    Stable keys provide that identity:

    tsx
    key={course.id}

    Conceptually:

    text
    A → same
    B → removed
    C → same
    D → new

    Keys are particularly important during reconciliation.

    Nested Rendering

    Consider:

    tsx
    function App() {
    return <Dashboard />;
    }
    function Dashboard() {
    return (
    <main>
    <Header />
    <CourseList />
    </main>
    );
    }

    The rendering chain becomes:

    text
    App
    ↓
    Dashboard
    ├── Header
    └── CourseList

    React evaluates the component hierarchy and determines the resulting UI tree.

    Rendering Children

    A component can receive children:

    tsx
    function Card({
    children
    }: {
    children: React.ReactNode;
    }) {
    return (
    <article className="card">
    {children}
    </article>
    );
    }

    Usage:

    tsx
    <Card>
    <h2>React</h2>
    <p>Learn React rendering.</p>
    </Card>

    The child content becomes part of the rendered tree.

    Rendering Text

    React can render strings and numbers:

    tsx
    <h1>{title}</h1>
    <p>{count}</p>

    For example:

    text
    title = "React"
    count = 10

    produces:

    text
    React
    10

    But arbitrary objects aren't valid normal React children:

    tsx
    <p>{user}</p>

    Instead:

    tsx
    <p>{user.name}</p>

    Rendering null

    A component can intentionally render nothing:

    tsx
    function AdminPanel({
    isAdmin
    }: {
    isAdmin: boolean;
    }) {
    if (!isAdmin) {
    return null;
    }
    return <section>Admin Panel</section>;
    }

    When:

    text
    isAdmin = false

    the component produces no visible UI.

    Rendering false

    This pattern is common:

    tsx
    {isAdmin && <AdminPanel />}

    If:

    text
    isAdmin = false

    React doesn't display the boolean value.

    However, be careful with values such as 0:

    tsx
    {items.length && <List />}

    If items.length is 0, you may end up rendering 0.

    Prefer:

    tsx
    {items.length > 0 && <List />}

    Rendering and Browser Paint

    The complete process involves more than React.

    A simplified model:

    text
    State
    ↓
    React Render
    ↓
    Reconciliation
    ↓
    React Commit
    ↓
    DOM
    ↓
    Browser Layout
    ↓
    Browser Paint
    ↓
    Screen

    This distinction matters when diagnosing performance.

    A slow application may be caused by:

    text
    React rendering
    JavaScript computation
    DOM size
    Layout
    Paint
    Network

    React DevTools only gives you part of the picture.

    React Reconciliation

    Reconciliation is the process React uses to determine how the current rendered result differs from the previous one.

    Conceptually:

    text
    Previous UI
    +
    New UI
    ↓
    Reconciliation
    ↓
    Required changes

    For example:

    text
    Previous:
    <h1>Count: 1</h1>
    New:
    <h1>Count: 2</h1>

    React identifies that the text needs to change.

    Reconciliation Is Not Simply "Compare HTML"

    React isn't simply comparing two HTML strings.

    It works with React's element/tree representation and uses rules involving:

    text
    Element type
    Keys
    Position
    Props
    Component structure

    This allows React to efficiently determine what needs to change.

    We'll study reconciliation and the modern React rendering model in much more depth later.

    Element Type Matters

    Suppose:

    tsx
    <div>React</div>

    becomes:

    tsx
    <section>React</section>

    The element type changed:

    text
    div
    ↓
    section

    React treats this differently from simply changing text.

    The type is one of the important inputs to reconciliation.

    Stable Component Structure

    Consider:

    tsx
    function App() {
    return (
    <main>
    <CourseList />
    </main>
    );
    }

    Then:

    text
    CourseList

    continues to occupy the same conceptual position in the tree.

    Stable structure and keys help React preserve appropriate component identity between renders.

    Rendering and Component Identity

    Consider:

    tsx
    <CourseCard key={course.id} />

    React uses the key along with the surrounding tree structure to determine component identity.

    This affects whether React can preserve things such as:

    text
    Component state
    DOM nodes
    Input values

    when list items change.

    This is why incorrect keys can produce subtle bugs.

    Example: Incorrect Keys

    Suppose:

    text
    Before:
    A
    B
    C

    Then:

    text
    After:
    X
    A
    B
    C

    If indexes are used as keys:

    text
    0 → X
    1 → A
    2 → B
    3 → C

    React can interpret the identity differently than you intended.

    With stable IDs:

    text
    A → A
    B → B
    C → C
    X → new

    The second approach better represents item identity.

    Rendering and State Preservation

    React's component identity determines whether state is preserved.

    For example:

    tsx
    <Counter />

    If the same component remains in the same conceptual position, React can preserve its state across renders.

    If the identity changes because the component type or key changes, React may reset that state.

    This becomes very important in:

    text
    Forms
    Tabs
    Lists
    Conditional UI
    Routing

    Initial Render vs Re-render

    Let's compare them.

    Initial render

    text
    Application starts
    ↓
    createRoot()
    ↓
    root.render()
    ↓
    Component tree evaluated
    ↓
    DOM created/updated

    Re-render

    text
    State/props/context change
    ↓
    React schedules update
    ↓
    Component tree evaluated as needed
    ↓
    Reconciliation
    ↓
    Commit changes

    The two processes are related but not identical.

    Does Every State Update Render the Entire Application?

    Not exactly.

    A state update doesn't mean React blindly recreates the entire DOM.

    React determines which parts of the tree need to be evaluated and which changes need to be committed.

    For example:

    text
    App
    ├── Header
    ├── CourseList
    └── Footer

    If a local state update occurs inside:

    text
    CourseList

    React doesn't necessarily need to update the DOM for:

    text
    Header
    Footer

    Only the necessary parts of the rendered tree are ultimately committed.

    Does Every Component Re-render?

    This is more nuanced.

    A parent rendering can cause React to evaluate descendants by default.

    But React has mechanisms that can prevent unnecessary work.

    Examples include:

    text
    React.memo
    useMemo
    useCallback
    State placement
    Component boundaries
    Context design
    External stores

    Don't memorize these yet.

    First understand:

    Rendering is normal React behavior. Optimization comes after measuring.

    React Strict Mode

    Vite React projects often start with:

    tsx
    <StrictMode>
    <App />
    </StrictMode>

    Strict Mode enables additional development-only checks.

    One behavior developers commonly notice is that certain render-related functions may appear to run more than once during development.

    This is intentional.

    It helps reveal code that incorrectly relies on rendering being executed exactly once.

    Strict Mode Does Not Mean Production Double Rendering

    A common misconception is:

    React always renders components twice.

    That's incorrect.

    Strict Mode's extra checks are development-oriented behavior.

    Don't remove Strict Mode simply because you see additional development behavior.

    Instead, use it to identify code that isn't safe or pure during rendering.

    Rendering With React Developer Tools

    Remember the previous lesson.

    If you have:

    text
    Dashboard
    └── CourseList
    ├── CourseCard
    ├── CourseCard
    └── CourseCard

    React DevTools can help you inspect the component tree.

    The Profiler can help you investigate:

    text
    Which components rendered?
    How often?
    How expensive?

    This makes rendering behavior observable.

    Debugging a Rendering Problem

    Suppose:

    I changed the course filter, but the UI isn't updating.

    Use this workflow:

    text
    Filter changed
    ↓
    Did state change?
    ↓
    React DevTools
    ↓
    Check state
    ↓
    Did component render?
    ↓
    Check props
    ↓
    Check API/network
    ↓
    Check derived data
    ↓
    Check JSX condition

    This is much better than randomly modifying code.

    Example: State Not Updating

    Consider:

    tsx
    const [course, setCourse] = useState({
    title: "React"
    });

    Then someone does:

    tsx
    course.title = "Angular";
    setCourse(course);

    This mutates the existing object.

    React state should generally be updated immutably:

    tsx
    setCourse({
    ...course,
    title: "Angular"
    });

    This creates a new object reference.

    The distinction between mutation, identity, and rendering will become very important later.

    Rendering and Immutability

    React development commonly follows the principle:

    text
    Don't mutate state directly.
    Create a new state value.

    For example:

    Incorrect:

    tsx
    courses.push(newCourse);
    setCourses(courses);

    Better:

    tsx
    setCourses([
    ...courses,
    newCourse
    ]);

    This makes state changes easier for React and developers to reason about.

    Rendering and Derived Data

    Suppose:

    tsx
    const [courses, setCourses] = useState<Course[]>([]);
    const [search, setSearch] = useState("");

    You can derive:

    tsx
    const filteredCourses =
    courses.filter(course =>
    course.title
    .toLowerCase()
    .includes(search.toLowerCase())
    );

    Then:

    tsx
    return (
    <CourseList
    courses={filteredCourses}
    />
    );

    The model is:

    text
    State
    ├── courses
    └── search
    ↓
    Derived Data
    ↓
    JSX
    ↓
    UI

    Derived values should generally be calculated from current state rather than duplicated unnecessarily.

    Rendering and API Data

    A common enterprise flow is:

    text
    API
    ↓
    State / Server Cache
    ↓
    Component
    ↓
    JSX
    ↓
    Render

    For example:

    tsx
    function CoursePage() {
    const {
    courses,
    loading
    } = useCourses();
    if (loading) {
    return <Loading />;
    }
    return (
    <CourseList courses={courses} />
    );
    }

    The UI changes as the data state changes.

    Loading → Success

    Initially:

    text
    loading = true
    courses = []

    React renders:

    text
    Loading...

    Then API response arrives:

    text
    loading = false
    courses = [...]

    React renders again:

    text
    Course List

    The lifecycle becomes:

    text
    Initial state
    ↓
    Render Loading
    ↓
    API response
    ↓
    State update
    ↓
    Render CourseList
    ↓
    Commit UI changes

    This is one of the most common rendering patterns in real applications.

    Loading → Error

    Similarly:

    text
    loading = true
    ↓
    Loading UI
    ↓
    API fails
    ↓
    error state
    ↓
    Error UI

    For production components, think in terms of:

    text
    Loading
    Error
    Empty
    Success

    rather than only:

    text
    Success

    Rendering Performance

    Rendering performance becomes important when applications become large.

    For example:

    text
    Dashboard
    ├── 10 charts
    ├── 5 tables
    ├── 1,000 rows
    ├── filters
    └── notifications

    A small state change can potentially trigger expensive work.

    The right approach is:

    text
    Measure
    ↓
    Identify bottleneck
    ↓
    Understand cause
    ↓
    Optimize
    ↓
    Measure again

    Not:

    text
    Add memo everywhere

    Common Rendering Performance Techniques

    Later we'll study each in depth.

    Important techniques include:

    text
    Component decomposition
    State colocation
    React.memo
    useMemo
    useCallback
    List virtualization
    Code splitting
    Lazy loading
    Efficient data fetching
    Caching
    Avoiding unnecessary effects

    But optimization should be evidence-driven.

    Rendering and Large Lists

    Suppose an API returns:

    text
    10,000 courses

    Rendering all 10,000 rows can be expensive.

    Instead, consider:

    text
    Server-side pagination
    OR
    Virtualization
    OR
    Incremental loading

    Conceptually:

    text
    10,000 records
    ↓
    Only relevant subset
    ↓
    React renders visible UI
    ↓
    Browser

    This becomes important in enterprise React applications.

    Rendering and Virtualization

    For very large lists:

    text
    10,000 rows

    you might render only:

    text
    Visible rows
    +
    Small buffer

    For example:

    text
    Viewport
    ┌─────────────────┐
    │ Row 401 │
    │ Row 402 │
    │ Row 403 │
    │ Row 404 │
    │ Row 405 │
    └─────────────────┘
    Not all 10,000 DOM nodes.

    This can dramatically reduce DOM work.

    Rendering and Server-Side Pagination

    Another approach:

    text
    GET /courses?page=1&size=50

    Instead of:

    text
    GET /courses
    → 10,000 records

    The server returns only what the user needs.

    This is often preferable for enterprise systems because it reduces:

    text
    Network payload
    Memory usage
    Rendering work
    Database response size

    Rendering and URL State

    Suppose:

    text
    /courses?page=2&search=react

    The URL contains:

    text
    page = 2
    search = react

    The component renders based on those values.

    Conceptually:

    text
    URL
    ↓
    Router
    ↓
    State/Derived State
    ↓
    JSX
    ↓
    UI

    This is especially useful for searchable and filterable applications.

    Rendering and Accessibility

    Rendering isn't only about visual output.

    When React changes the UI dynamically, consider:

    text
    Focus
    Screen readers
    ARIA
    Document title
    Keyboard navigation
    Loading announcements

    For example, if a modal appears:

    text
    State change
    ↓
    Modal rendered
    ↓
    Focus should move appropriately

    Good rendering architecture considers accessibility from the beginning.

    Rendering and Error Boundaries

    Large React applications should also think about rendering failures.

    Conceptually:

    text
    Application
    │
    ├── Header
    ├── Dashboard
    │ └── CourseWidget
    └── Footer

    If a particular UI subtree fails, an Error Boundary can provide a fallback rather than allowing the entire user experience to fail.

    Conceptually:

    text
    Error Boundary
    │
    ▼
    CourseWidget
    │
    X
    Error
    │
    ▼
    Fallback UI

    We'll study Error Boundaries separately.

    A Complete Rendering Example

    Consider:

    tsx
    function CoursePage() {
    const [courses, setCourses] = useState<Course[]>([]);
    const [loading, setLoading] = useState(true);
    useEffect(() => {
    loadCourses()
    .then(data => {
    setCourses(data);
    setLoading(false);
    });
    }, []);
    if (loading) {
    return <p>Loading...</p>;
    }
    return (
    <ul>
    {courses.map(course => (
    <li key={course.id}>
    {course.title}
    </li>
    ))}
    </ul>
    );
    }

    The lifecycle is:

    text
    Component starts
    ↓
    loading = true
    ↓
    Render "Loading..."
    ↓
    Effect starts API request
    ↓
    API response
    ↓
    setCourses(data)
    ↓
    setLoading(false)
    ↓
    Re-render
    ↓
    Map courses
    ↓
    Render list
    ↓
    Commit DOM changes

    This is real-world React rendering.

    The Render Cycle

    A useful simplified model:

    text
    ┌──────────────┐
    │ Initial Load │
    └──────┬───────┘
    │
    ▼
    Render
    │
    ▼
    Commit
    │
    ▼
    DOM
    │
    ▼
    User Action
    │
    ▼
    State Update
    │
    ▼
    Render
    │
    ▼
    Reconciliation
    │
    ▼
    Commit
    │
    ▼
    Updated DOM
    │
    └───────► User

    This loop is the heart of React.

    Important Correction: Render Is Not "Painting"

    A browser ultimately paints pixels to the screen.

    React's render phase does not paint pixels.

    The simplified layers are:

    text
    React
    ↓
    Determine UI
    ↓
    Commit DOM
    ↓
    Browser
    ↓
    Layout
    ↓
    Paint
    ↓
    Compositing

    Keeping these layers separate helps when analyzing performance.

    React Rendering vs Browser Rendering

    Don't confuse:

    React rendering

    text
    Component
    ↓
    React elements
    ↓
    Reconciliation

    with:

    Browser rendering

    text
    DOM
    ↓
    Style calculation
    ↓
    Layout
    ↓
    Paint
    ↓
    Composite

    Both are involved in getting pixels onto the screen.

    Interview questions & answers

    Interview preparation

    14 questions grouped by difficulty — expand any card for a model answer and follow-up probe.

    Beginner

    4
    1. 1What is rendering in React?
      Beginner

      Model answer

      Rendering is the process where React evaluates components using their current props and state to determine what the UI should look like.

    2. 2What is the initial render?
      Beginner

      Model answer

      The initial render is the first time React evaluates the application's component tree and commits the resulting UI to the DOM.

    3. 3What causes a React component to re-render?
      Beginner

      Model answer

      Common causes include state updates, changed props, context updates, parent renders, and updates from external stores.

    4. 4Does re-rendering mean the entire DOM is recreated?
      Beginner

      Model answer

      No.

      React determines what changed and commits only the necessary DOM updates.

    Intermediate

    4
    1. 5Explain render phase and commit phase.
      Intermediate

      Model answer

      During the render phase, React evaluates components and determines the next UI representation.

      During the commit phase, React applies the necessary changes to the DOM or other rendering environment.

    2. 6Why should rendering be pure?
      Intermediate

      Model answer

      React may evaluate rendering logic multiple times, so rendering should produce the UI from its inputs without causing side effects.

      Side effects should be handled through appropriate mechanisms such as event handlers or effects.

    3. 7What is reconciliation?
      Intermediate

      Model answer

      Reconciliation is the process React uses to compare the previous rendered result with the new result and determine what changes need to be committed.

    4. 8Does every render cause a DOM update?
      Intermediate

      Model answer

      No.

      React may render a component and determine that there are no necessary DOM changes.

    Advanced

    6
    1. 9What happens when state changes?
      Advanced

      Model answer

      A state update schedules React to update the affected component tree.

      React evaluates the relevant components again, produces a new UI representation, reconciles it with the previous result, and commits the necessary changes to the DOM.

    2. 10How would you debug unnecessary renders?
      Advanced

      Model answer

      I'd use React DevTools and the Profiler to measure which components render and how expensive they are.

      Then I'd investigate parent renders, state placement, prop identity, context updates, and derived computations before applying targeted optimizations.

    3. 11Why is immutability important in React state?
      Advanced

      Model answer

      Creating new state values makes changes explicit and gives React and related optimization mechanisms clear identity changes to work with.

      Direct mutation can lead to difficult-to-reason-about updates and stale UI.

    4. 12How would you explain React rendering to a junior developer?
      Advanced

      Model answer

      I'd explain it as: React takes the current state and props, evaluates the components to determine the desired UI, compares that result with the previous one, and then updates only what needs to change in the DOM.

    5. 13How would you optimize a slow React rendering path?
      Advanced

      Model answer

      First I'd measure it using React Profiler and browser performance tools.

      Then I'd identify whether the bottleneck is component rendering, expensive calculations, large lists, network/data processing, or browser layout and paint.

      Based on the actual bottleneck, I'd apply techniques such as state colocation, memoization, virtualization, code splitting, or data-fetching improvements.

    6. 14Does React guarantee that a component renders only once?
      Advanced

      Model answer

      No.

      Components can render multiple times as application state, props, context, or other dependencies change.

      Development Strict Mode can also intentionally invoke certain logic more than once to expose unsafe patterns.

    Senior Scenario Question

    Interviewer:

    A React page is slow whenever the user changes a filter. How would you investigate?

    A strong answer:

    I wouldn't immediately add memoization. I'd first reproduce the issue and measure it using React DevTools Profiler and browser performance tools. I'd identify which components are rendering and which operations are expensive. Then I'd check whether the filter is triggering unnecessary API calls, expensive calculations, large list rendering, or unnecessary child renders. If it's a large dataset, I'd consider server-side filtering or pagination and possibly virtualization. If it's unnecessary rendering, I'd review state placement, prop identity, context usage, and memoization. After making the change, I'd profile again to verify that the optimization actually improved the problem.

    That answer demonstrates engineering maturity because it focuses on measurement and root cause, not just React keywords.

    Practical Exercise

    Create this component:

    tsx
    import { useState } from "react";
    function Counter() {
    const [count, setCount] = useState(0);
    return (
    <section>
    <h1>Counter</h1>
    <p>
    Count: {count}
    </p>
    <button
    onClick={() =>
    setCount(count + 1)
    }
    >
    Increment
    </button>
    </section>
    );
    }

    Now observe:

    Initial

    text
    count = 0
    ↓
    Render
    ↓
    Count: 0

    Click

    text
    setCount(1)
    ↓
    Render
    ↓
    Count: 1

    Click again

    text
    setCount(2)
    ↓
    Render
    ↓
    Count: 2

    Use React Developer Tools to observe the component.

    Then use the Profiler to record the interaction.

    Advanced Exercise

    Create:

    tsx
    function Parent() {
    const [count, setCount] = useState(0);
    return (
    <>
    <button
    onClick={() =>
    setCount(count + 1)
    }
    >
    {count}
    </button>
    <Child />
    </>
    );
    }
    function Child() {
    return (
    <div>
    Child Component
    </div>
    );
    }

    Use React DevTools to observe the component tree.

    Then ask:

    text
    When Parent state changes:
    ↓
    Does Parent render?
    ↓
    Does Child render?
    ↓
    Does Child's DOM change?

    This exercise will prepare you for:

    text
    React.memo
    Memoization
    Component boundaries
    State colocation
    Rendering optimization

    Advanced Exercise — List Rendering

    Create:

    tsx
    const courses = Array.from(
    { length: 1000 },
    (_, index) => ({
    id: index,
    title: `Course ${index}`
    })
    );

    Render:

    tsx
    <ul>
    {courses.map(course => (
    <li key={course.id}>
    {course.title}
    </li>
    ))}
    </ul>

    Then profile the component.

    Ask:

    text
    What happens with 10 items?
    What happens with 1,000?
    What happens with 10,000?

    This introduces the real-world problem of large-list rendering.

    Rendering Architecture

    At the application level:

    text
    React Application
    │
    ▼
    State / Props
    │
    ▼
    Component Tree
    │
    ▼
    JSX
    │
    ▼
    React Element Tree
    │
    ▼
    Render Phase
    │
    ▼
    Reconciliation
    │
    ▼
    Commit Phase
    │
    ▼
    DOM
    │
    ▼
    Browser Rendering
    │
    ┌─────────┴─────────┐
    ▼ ▼
    Layout Paint
    │ │
    └─────────┬─────────┘
    ▼
    Screen

    This is the architecture you should keep in your head.

    Final Mental Model

    Memorize this:

    text
    STATE / PROPS
    │
    ▼
    COMPONENT
    │
    ▼
    JSX
    │
    ▼
    REACT ELEMENTS
    │
    ▼
    RENDER PHASE
    │
    ▼
    RECONCILIATION
    │
    ▼
    COMMIT PHASE
    │
    ▼
    DOM
    │
    ▼
    BROWSER PAINT
    │
    ▼
    SCREEN

    And when the user interacts:

    text
    USER ACTION
    ↓
    EVENT HANDLER
    ↓
    STATE UPDATE
    ↓
    RENDER
    ↓
    RECONCILIATION
    ↓
    COMMIT
    ↓
    UPDATED UI

    The most important principle is:

    React rendering is not "React rewriting the HTML." React evaluates components to determine the desired UI, reconciles that result with the previous one, and commits only the necessary changes to the rendering environment.

    This distinction will become the foundation for understanding Virtual DOM, reconciliation, state, props, hooks, component lifecycle, and React performance.

    Ready to mark this lesson complete?Track your journey across the entire course.