Topic 3 of 56 · Full Stack Advanced

Topic 3 : React Components

Lesson TL;DRTopic 3: React Components 📖 9 min read · 🎯 beginner · 🧭 Prerequisites: phpwithselectfetch, postmanconfiguration Why this matters Up until now, you've probably seen a big React file and thought — wh...
9 min read·beginner·react · components · props · state

Topic 3: React Components

📖 9 min read · 🎯 beginner · 🧭 Prerequisites: php-with-select-fetch, postman-configuration

Why this matters

Up until now, you've probably seen a big React file and thought — where do I even start? Here's the thing: React doesn't expect you to write everything in one place. It lets you break your UI into small, reusable pieces called components. Think of it like building with LEGO blocks — each block does one thing, and you snap them together to build something big. In this lesson, we'll cover how components work, how they talk to each other through props and state, how they respond to user actions, and when they come alive or get removed from the screen.

What You'll Learn

  • Distinguish between functional components and class components and know when to use each
  • Pass data between components using props
  • Manage dynamic data inside a component using state
  • Attach event handlers to user interactions
  • Understand React's component lifecycle and its key methods

The Analogy

Think of React components like the modular rooms in a Lego house. Each room (component) is self-contained — it has its own walls, furniture, and purpose. You can snap a bedroom into one house and reuse the exact same blueprint in another house across town. You can even hand a room a nameplate (props) so it knows whose bedroom it is. And some rooms have a thermostat (state) that tracks and responds to changes happening inside them — when the temperature shifts, the room reacts immediately. The whole house (your app) is just rooms snapped together.

Chapter 1: Introduction to React Components

In React, components are the fundamental building blocks of any UI. Every button, form, header, and page section you see in a React app is a component. Components come in two main flavors:

  • Functional components — plain JavaScript functions that accept props and return JSX
  • Class components — ES6 classes that extend React.Component, capable of holding state and lifecycle methods

Both types produce the same rendered output; the difference is in how they manage internal logic. Modern React heavily favors functional components (especially with Hooks), but class components are still found in many production codebases and are important to understand.

graph TD
    App["App (root component)"]
    App --> FunctionalGreeting
    App --> ClassGreeting
    App --> GreetingWithProps
    App --> StatefulCounter
    App --> ClickHandler
    App --> LifecycleComponent

Chapter 2: Functional Components

Functional components are simple JavaScript functions that return JSX. They are typically used for presentational purposes — rendering UI based on whatever data they receive.

src/components/FunctionalGreeting.js:

import React from 'react';

function FunctionalGreeting() {
    return <h1>Hello, Vizag!</h1>;
}

export default FunctionalGreeting;

Integrating FunctionalGreeting into App

The class plugged the new component into the root App component:

src/App.js:

import React from 'react';
import './App.css';
import FunctionalGreeting from './components/FunctionalGreeting';

function App() {
    return (
        <div className="App">
            <FunctionalGreeting />
        </div>
    );
}

export default App;

Rendering <FunctionalGreeting /> is identical to calling FunctionalGreeting() — React just uses the JSX tag syntax to keep things readable.

Chapter 3: Class Components

Class components are ES6 classes that extend React.Component. They must implement a render() method that returns JSX. They can hold their own state and hook into React's lifecycle methods — capabilities that originally made them the dominant pattern before Hooks arrived.

src/components/ClassGreeting.js:

import React, { Component } from 'react';

class ClassGreeting extends Component {
    render() {
        return <h1>Hello, Vizag from a Class Component!</h1>;
    }
}

export default ClassGreeting;

Integrating ClassGreeting into App

src/App.js:

import React from 'react';
import './App.css';
import FunctionalGreeting from './components/FunctionalGreeting';
import ClassGreeting from './components/ClassGreeting';

function App() {
    return (
        <div className="App">
            <FunctionalGreeting />
            <ClassGreeting />
        </div>
    );
}

export default App;

Both components now render their respective headings one after another in the browser.

Chapter 4: Props

Props (short for properties) are read-only attributes used to pass data from a parent component to a child component. They give components dynamic behavior without requiring the child to manage its own data. A component that receives props via its function argument can use them directly inside JSX with curly-brace interpolation.

src/components/GreetingWithProps.js:

import React from 'react';

function GreetingWithProps(props) {
    return <h1>Hello, {props.name}!</h1>;
}

export default GreetingWithProps;

Integrating GreetingWithProps into App

The parent passes a name prop as a JSX attribute:

src/App.js:

import React from 'react';
import './App.css';
import FunctionalGreeting from './components/FunctionalGreeting';
import ClassGreeting from './components/ClassGreeting';
import GreetingWithProps from './components/GreetingWithProps';

function App() {
    return (
        <div className="App">
            <FunctionalGreeting />
            <ClassGreeting />
            <GreetingWithProps name="Vizag" />
        </div>
    );
}

export default App;

Changing name="Vizag" to name="Alice" would instantly update the rendered heading — no changes to GreetingWithProps required. That's the power of props.

Key rules about props:

  • Props flow down — from parent to child only
  • Props are read-only inside the receiving component — never mutate them
  • Any JavaScript value can be a prop: strings, numbers, arrays, objects, functions, or even other components

Chapter 5: State

State is a built-in mechanism for storing data that can change over time inside a component. When state changes, React automatically re-renders the component to reflect the new data. In class components, state is initialized in the constructor and updated with this.setState().

src/components/StatefulCounter.js:

import React, { Component } from 'react';

class StatefulCounter extends Component {
    constructor(props) {
        super(props);
        this.state = {
            count: 0
        };
    }

    increment = () => {
        this.setState({ count: this.state.count + 1 });
    };

    render() {
        return (
            <div>
                <h1>Count: {this.state.count}</h1>
                <button onClick={this.increment}>Increment</button>
            </div>
        );
    }
}

export default StatefulCounter;

Key mechanics at play here:

  • this.state = { count: 0 } sets the initial state in the constructor
  • this.setState(...) schedules a re-render with the new state value — never mutate this.state directly
  • increment is defined as a class field arrow function so that this is correctly bound without needing .bind(this) in the constructor

Integrating StatefulCounter into App

src/App.js:

import React from 'react';
import './App.css';
import FunctionalGreeting from './components/FunctionalGreeting';
import ClassGreeting from './components/ClassGreeting';
import GreetingWithProps from './components/GreetingWithProps';
import StatefulCounter from './components/StatefulCounter';

function App() {
    return (
        <div className="App">
            <FunctionalGreeting />
            <ClassGreeting />
            <GreetingWithProps name="Vizag" />
            <StatefulCounter />
        </div>
    );
}

export default App;

Each click of the "Increment" button updates count, which triggers a re-render showing the new value.

Chapter 6: Handling Events

React components handle user interactions using event handlers — functions attached to JSX elements via props like onClick, onChange, onSubmit, and more. The syntax mirrors standard HTML events but uses camelCase naming.

src/components/ClickHandler.js:

import React, { Component } from 'react';

class ClickHandler extends Component {
    handleClick = () => {
        alert('Button was clicked!');
    };

    render() {
        return (
            <div>
                <button onClick={this.handleClick}>Click Me</button>
            </div>
        );
    }
}

export default ClickHandler;

Notice that onClick={this.handleClick} passes the function reference — no parentheses. Writing onClick={this.handleClick()} would call the function immediately during render, not on click.

Integrating ClickHandler into App

src/App.js:

import React from 'react';
import './App.css';
import FunctionalGreeting from './components/FunctionalGreeting';
import ClassGreeting from './components/ClassGreeting';
import GreetingWithProps from './components/GreetingWithProps';
import StatefulCounter from './components/StatefulCounter';
import ClickHandler from './components/ClickHandler';

function App() {
    return (
        <div className="App">
            <FunctionalGreeting />
            <ClassGreeting />
            <GreetingWithProps name="Vizag" />
            <StatefulCounter />
            <ClickHandler />
        </div>
    );
}

export default App;

Chapter 7: Component Lifecycle

Every React class component goes through a predictable lifecycle: it mounts (appears in the DOM), optionally updates (when props or state change), and eventually unmounts (is removed from the DOM). React exposes lifecycle methods you can override to run code at each stage.

stateDiagram-v2
    [*] --> Constructor
    Constructor --> Render: initialize state
    Render --> componentDidMount: first paint
    componentDidMount --> Render: setState triggers update
    Render --> componentDidUpdate: re-render complete
    componentDidUpdate --> componentWillUnmount: component removed
    componentWillUnmount --> [*]

src/components/LifecycleComponent.js:

import React, { Component } from 'react';

class LifecycleComponent extends Component {
    constructor(props) {
        super(props);
        this.state = {
            data: null
        };
        console.log('Constructor');
    }

    componentDidMount() {
        console.log('componentDidMount');
        // Simulate an API call
        setTimeout(() => {
            this.setState({ data: 'Data fetched' });
        }, 2000);
    }

    componentDidUpdate(prevProps, prevState) {
        console.log('componentDidUpdate');
        if (prevState.data !== this.state.data) {
            console.log('Data has been updated');
        }
    }

    componentWillUnmount() {
        console.log('componentWillUnmount');
    }

    render() {
        console.log('Render');
        return (
            <div>
                <h1>Lifecycle Methods</h1>
                <p>{this.state.data || 'Loading...'}</p>
            </div>
        );
    }
}

export default LifecycleComponent;

What each method does:

MethodWhen it runsCommon use
constructorBefore first renderInitialize state, bind methods
renderEvery render (initial + updates)Return JSX
componentDidMountAfter first render, DOM is readyAPI calls, subscriptions, timers
componentDidUpdateAfter every re-renderReact to prop/state changes
componentWillUnmountBefore removal from DOMCleanup timers, cancel subscriptions

Integrating LifecycleComponent into App

The class used useState in the root App to toggle LifecycleComponent on and off — which triggers componentWillUnmount when toggled off, demonstrating the full lifecycle:

src/App.js:

import React, { useState } from 'react';
import './App.css';
import FunctionalGreeting from './components/FunctionalGreeting';
import ClassGreeting from './components/ClassGreeting';
import GreetingWithProps from './components/GreetingWithProps';
import StatefulCounter from './components/StatefulCounter';
import ClickHandler from './components/ClickHandler';
import LifecycleComponent from './components/LifecycleComponent';

function App() {
    const [showLifecycle, setShowLifecycle] = useState(true);

    return (
        <div className="App">
            <FunctionalGreeting />
            <ClassGreeting />
            <GreetingWithProps name="Vizag" />
            <StatefulCounter />
            <ClickHandler />
            {showLifecycle && <LifecycleComponent />}
            <button onClick={() => setShowLifecycle(!showLifecycle)}>
                Toggle Lifecycle Component
            </button>
        </div>
    );
}

export default App;

Open your browser's DevTools console while clicking "Toggle Lifecycle Component" and watch the lifecycle messages fire in sequence: Constructor → Render → componentDidMount → (2s pause) → componentDidUpdate → componentWillUnmount.

🧪 Try It Yourself

Task: Build a TemperatureDisplay class component that:

  1. Initializes state with { tempC: 20 }
  2. Renders the temperature in both Celsius and Fahrenheit (F = C × 9/5 + 32)
  3. Provides "Warmer" and "Cooler" buttons that increment/decrement tempC by 1

Success criterion: Clicking "Warmer" should show 21°C / 69.8°F, clicking "Cooler" from 20 should show 19°C / 66.2°F. Both values update simultaneously with each click.

Starter snippet:

import React, { Component } from 'react';

class TemperatureDisplay extends Component {
    constructor(props) {
        super(props);
        this.state = { tempC: 20 };
    }

    // Add warmer and cooler handlers here

    render() {
        const { tempC } = this.state;
        const tempF = /* your formula here */;
        return (
            <div>
                <h2>{tempC}°C / {tempF}°F</h2>
                {/* Add your buttons here */}
            </div>
        );
    }
}

export default TemperatureDisplay;

🔍 Checkpoint Quiz

Q1. What is the key structural difference between a functional component and a class component in React?

A) Functional components cannot receive props; class components can
B) Functional components are plain JS functions returning JSX; class components extend React.Component and require a render() method
C) Class components are faster at rendering than functional components
D) Functional components can only be used once per application


Q2. Given the following code, what will the browser display immediately after mounting, and what will it display after 2 seconds?

class Mystery extends Component {
    constructor(props) {
        super(props);
        this.state = { message: null };
    }
    componentDidMount() {
        setTimeout(() => this.setState({ message: 'Ready!' }), 2000);
    }
    render() {
        return <p>{this.state.message || 'Loading...'}</p>;
    }
}

A) "Ready!" immediately, then nothing after 2 seconds
B) Nothing at all — state is null so nothing renders
C) "Loading..." immediately, then "Ready!" after 2 seconds
D) An error, because null cannot be used as initial state


Q3. What is wrong with the following event handler attachment?

<button onClick={this.handleClick()}>Submit</button>

A) handleClick should be an arrow function
B) The parentheses cause handleClick to be called immediately during render, not on click
C) onClick is not a valid React event prop
D) Nothing is wrong — this is correct React syntax


Q4. You're building a UserCard component that should display a user's name and avatar passed in from a parent. The data never changes inside UserCard itself. Should you use props or state for this, and why?

A1. B — Functional components are plain JS functions; class components extend React.Component and use a render() method. Both can receive props; the difference is in structure and how they handle internal logic.

A2. C — On mount, this.state.message is null, so the fallback 'Loading...' renders. After 2 seconds, setState fires, triggering a re-render that shows 'Ready!'.

A3. B — Writing onClick={this.handleClick()} invokes the function during the render phase and passes its return value (likely undefined) as the handler. The correct form is onClick={this.handleClick} — a reference, not a call.

A4. Use props. The data originates in the parent and is read-only inside UserCard. State is for data that the component itself owns and changes. Passing the name and avatar as props lets the parent control the data while keeping UserCard a pure, reusable display component.

🪞 Recap

  • React components are the building blocks of any React UI — each one is an isolated, reusable piece of the interface
  • Functional components are plain JavaScript functions that return JSX; class components extend React.Component and require a render() method
  • Props pass read-only data from parent to child, making components dynamic and reusable
  • State holds data that belongs to and changes within a component; calling this.setState() schedules a re-render
  • Event handlers like onClick connect user interactions to component logic — always pass a function reference, never a call
  • Class components expose lifecycle methods (componentDidMount, componentDidUpdate, componentWillUnmount) to run code at specific moments in a component's life

📚 Further Reading

Like this topic? It’s one of 56 in Full Stack Advanced.

Block your seat for ₹2,500 and join the next cohort.