Component is a reusable JavaScript Function or class that accepts Props and returns React JSX elements describing what should appear on the screen.
They are just standard JavaScript functions describing UI.
// 1. Define the component
function Welcome(props) {
return <h1>Hello, {props.name}</h1>;
}
// OR using Arrow Functions (Preferred by many)
const Welcome = (props) => {
return <h1>Hello, {props.name}</h1>;
};
// 2. Use it
// <Welcome name="Sara" />render() method.useState and useEffect to handle data.Earlier, whenever we needed state, we had to use a Class Component.
class Welcome extends React.Component {
render() {
// We access props via 'this.props'
return <h1>Hello, {this.props.name}</h1>;
}
}this Confusion: We often have to bind methods manually (e.g., this.handleClick.bind(this)).componentDidMount, componentWillUnmount.| Feature | Functional Components | Class Components |
|---|---|---|
| Syntax | Plain JS Function | ES6 Class |
| State Management | useState Hook | this.state |
| Side Effects | useEffect Hook | Lifecycle Methods (componentDidMount) |
| Boilerplate | Low (Minimal code) | High (Classes, render, this) |
| Performance | Slightly faster (less overhead) | Slightly heavier |
| Best Practice | Yes (Default for new apps) | No (Legacy/Maintenance only) |
In React, we don't use inheritance (like class AdminUser extends User). We use Composition.
Composition means building complex components from simpler ones.
This is a special prop that allows us to pass elements inside our component's opening and closing tags.
The Container (Wrapper):
const Card = (props) => {
return (
<div className="card-box">
{/* This renders whatever is put inside <Card>...</Card> */}
{props.children}
</div>
);
};The Usage:
const App = () => {
return (
<Card>
{/* All of this is passed as 'props.children' to Card */}
<h2>User Profile</h2>
<p>Name: John Doe</p>
</Card>
);
};This pattern is critical for creating reusable layouts (like Modals, Cards, or Layout Wrappers) where the container doesn't care what is inside it.
Here is a full example of a React Class Component written in TypeScript. It uses interface for typing Props and State.
This version uses a Constructor to initialize state, which was the standard pattern for many years.
"use client";
import { Button } from "@/components/ui/button";
import { Component, ReactNode } from "react";
// 1. Define Types for Props and State
interface CounterProps {
initialCount?: number;
}
interface CounterState {
count: number;
}
class CounterComponent extends Component<CounterProps, CounterState> {
// 2. Constructor: Used to initialize state and bind methods (if not using arrows)
constructor(props: CounterProps) {
super(props); // Must call super to access 'this'
this.state = {
count: 0,
};
}
// Runs ONCE after the component renders for the first time.
// We use this for API calls, timers, or subscriptions.
componentDidMount() {
console.log("Mounted! (Equivalent to useEffect with [])");
}
// Runs whenever State or Props change.
// We often check prevProps vs this.props here to avoid infinite loops.
componentDidUpdate(prevProps: CounterProps, prevState: CounterState) {
if (prevState.count !== this.state.count) {
console.log(`Count changed: ${prevState.count} -> ${this.state.count}`);
console.log("Updated! (Equivalent to useEffect with [count])");
}
}
// Runs just before the component is removed from the DOM.
componentWillUnmount() {
console.log("Cleanup! (Equivalent to useEffect return function)");
}
// 3. Methods: Defined as Arrow Functions to auto-bind 'this'
increment = () => {
this.setState({ count: this.state.count + 1 });
};
decrement = () => {
this.setState({ count: this.state.count - 1 });
};
render(): ReactNode {
return (
<div className="p-4 border rounded flex flex-col gap-1 justify-center">
<h1 className="text-4xl text-center">{this.state.count}</h1>
<div className="flex gap-1">
<Button
onClick={this.increment}
variant="outline"
className="rounded bg-muted/5 hover:bg-muted/30 transition-all duration-300"
>
+
</Button>
<Button
onClick={this.decrement}
variant="outline"
className="rounded bg-muted/5 hover:bg-muted/30 transition-all duration-300"
>
-
</Button>
</div>
</div>
);
}
}
export default CounterComponent;| Concept | Definition | Key Takeaway |
|---|---|---|
| Component | A reusable piece of UI. | Splits UI into independent, isolated pieces. |
| Functional Component | A function returning JSX. | The modern standard. Uses Hooks. |
| Class Component | A class with a render() method. | Legacy. Uses this and lifecycle methods. |
| Composition | Nesting components inside others. | Powerful pattern to reuse UI logic/layout. |
props.children | Special prop for nested content. | Allows components to act as wrappers. |
props.name without this, what will happen?We will get a ReferenceError: props is not defined.
props is not a variable passed into the render() function as an argument. It is a property stored on the instance of the class itself.this.props.this caused constant bugs. Functional components fix this because props is just a standard function argument.undefined or null? If so, what does React render?Answer:
null: Yes! This is the standard way to tell React to render nothing (hide the component). It is valid and common.undefined: In older React versions, returning undefined was considered an error (often meaning dev forgot the return statement). In modern React, it acts like null (renders nothing), but relies on implicit behavior. It is best practice to explicitly return null if we want to render nothing.