
WHO IS THIS COURSE FOR?
This course is perfect for:
Complete beginners with basic HTML, CSS, and JavaScript knowledge
Developers switching to React from other frameworks
Anyone who wants to build fast, scalable web apps
Students and professionals preparing for frontend job roles
You don’t need to have any prior experience in React —
we’ll start from zero and build up together.
WHAT MAKES THIS COURSE DIFFERENT?
This isn’t just another theoretical course.
You’ll learn through hands-on examples, mini-projects, and code-along sessions.
Every concept is explained clearly and practically —
so you not only understand the “how,” but also the “why.”
You’ll also get downloadable resources, quizzes, assignments, and lifetime access to all updates.
What is React and Why Use It?
In this lecture, you'll discover what ReactJS is, how it was developed by Facebook (Meta), and why it has become one of the most popular libraries in modern web development. Learn how React’s component-based architecture, Virtual DOM, and declarative approach make building fast, interactive, and scalable user interfaces easier than ever.
By the end of this lecture, you’ll understand:
The evolution and purpose of React
How React simplifies UI development compared to traditional JavaScript
The key benefits like performance, modularity, and reusability
Real-world use cases and examples from top companies like Netflix, Airbnb, and Instagram
Think of React as building with Lego blocks — reusable, flexible, and powerful for creating dynamic apps of any scale.
This topic explains the key features and benefits of ReactJS, a powerful JavaScript library for building modern user interfaces. You’ll learn how React’s component-based architecture, Virtual DOM, JSX, and Hooks make development faster, cleaner, and more efficient. The module also highlights React’s one-way data flow, developer tools, and advantages like performance, reusability, SEO-friendliness, and strong community support—making it one of the most popular choices for web and mobile app development.
This topic explains how to set up a React development environment using Node.js, npm, and Visual Studio Code (VS Code). You’ll learn to install these tools, verify their versions, and understand their roles in creating and managing React projects. The setup allows you to build, run, and debug React applications efficiently within VS Code using the built-in terminal and helpful extensions.
In this lesson, you’ll learn how to create your first React application using the create-react-app tool. This official React setup command automatically configures everything you need — like Webpack, Babel, and a local development server — so you can start coding right away. You’ll install your app using npx create-react-app, run it with npm start, and explore the project’s folder structure, including key files like App.js and index.js inside the src folder.
React Project Folder Structure Overview
Lecture Objectives:
By the end of this lecture, students will be able to:
Understand the default folder and file structure of a React project created using create-react-app.
Know the purpose of key files and directories.
Identify where to write custom code in a React app.
1. Introduction
Once you’ve created a React app using create-react-app,
you’ll see a number of files and folders generated automatically.
At first, it might look overwhelming —
but don’t worry!
In this lecture, we’ll walk through the structure step by step
and explain what each part does.
2. Folder Structure at a Glance
Here’s what the structure looks like after creating a new app:
my-app/
├── node_modules/
├── public/
├── src/
├── .gitignore
├── package.json
├── README.md
Let’s explore each of these in detail.
3. The node_modules/ Folder
This folder contains all dependencies required by your app.
It’s automatically created when you run npm install or npx create-react-app.
You should not modify anything inside this folder.
Note: This folder can become large, and it's ignored in version control using .gitignore.
4. The public/ Folder
This folder contains static files that do not get processed by Webpack.
Key files:
index.html
The main HTML file.
It contains a <div id="root"></div> where the React app is injected.
favicon.ico
The small icon shown in the browser tab.
manifest.json
Used for progressive web apps (PWA) and browser settings.
robots.txt
Tells search engines how to index your site.
You generally won’t modify most files here,
but you can customize index.html if needed.
5. The src/ Folder
This is where you’ll write most of your code.
Key files:
index.js
Entry point of the React app.
Renders the root component (<App />) into the DOM.
App.js
Main component that acts as the base of your app.
You’ll often modify and expand this file as your project grows.
App.css
Styles for the App component.
index.css
Global styles for the application.
You can also create your own folders inside src/
to organize components, pages, assets, and more.
Example:
src/
├── components/
├── pages/
├── assets/
├── utils/
6. Configuration Files (Outside Folders)
package.json
Lists all the dependencies of your project.
Defines scripts like npm start, npm run build, etc.
.gitignore
Specifies which files/folders should be ignored by Git.
README.md
Contains project documentation.
This file is optional but helpful, especially in team projects.
7. Summary Table
Folder/File
Purpose
node_modules/
All installed packages
public/
Static files, index.html
src/
Your main app code (JSX, CSS, Components)
package.json
Project metadata and dependency list
.gitignore
Tells Git which files to ignore
README.md
Project description and instructions
8. Best Practice Tip
Keep your src/ folder well-organized.
As your app grows, group your components and files into subfolders.
This keeps your code clean, modular, and maintainable.
JSX is a syntax extension for JavaScript that lets you write HTML-like code inside your JavaScript files. It simplifies UI creation in React by allowing developers to describe the interface directly within component functions, instead of manually manipulating the DOM.
JSX is not valid JavaScript by itself — tools like Babel convert it into standard JavaScript (React.createElement() calls). It makes code cleaner, shorter, and more readable.
Rendering Elements in React
Lecture Objectives:
By the end of this lecture, students will be able to:
Understand how React renders elements to the DOM.
Use ReactDOM.createRoot() and root.render() effectively.
Know the difference between React elements and components.
Dynamically render content using variables and expressions.
1. Introduction
One of the core tasks of any frontend framework is rendering elements to the screen.
In React, this process is efficient, declarative, and automatic
thanks to the virtual DOM and React’s rendering engine.
In this lecture, we’ll learn how elements are rendered in React,
and how they are updated when data changes.
2. What is a React Element?
A React element is the smallest building block in a React application.
It describes what you want to see on the screen.
It’s similar to a DOM element,
but it’s a plain object that React uses to construct the virtual DOM.
Example:
const element = <h1>Hello, React!</h1>;
This JSX code creates a React element behind the scenes
using React.createElement().
React elements are immutable — once created, they cannot be changed.
3. Rendering React Elements to the DOM
React uses the react-dom library to render elements into the browser’s DOM.
Starting with React 18, the recommended way to render an element is:
import React from 'react';
import ReactDOM from 'react-dom/client';
const element = <h1>Hello, world!</h1>;
const root = ReactDOM.createRoot(document.getElementById('root'));
root.render(element);
Step-by-step:
ReactDOM.createRoot(...) connects React to a real DOM node.
.render(element) tells React what to show inside that node.
The HTML file must contain a <div id="root"></div> element.
This is usually found in the public/index.html file.
4. Dynamic Content Rendering
You can also render variables, functions, and expressions inside JSX:
const name = "Sumaiyya";
const greeting = <h1>Hello, {name}!</h1>;
root.render(greeting);
React will evaluate {name} and replace it with the value before rendering.
5. Updating the UI
React’s rendering system is reactive.
When state or props change,
React automatically re-renders the affected components.
This allows your UI to stay in sync with your data.
We’ll learn more about state and props in upcoming lectures.
6. React Elements vs Components
A React element is just a description of what you want to render.
A component is a reusable function (or class) that returns React elements.
Example of a functional component:
function Welcome() {
return <h2>Welcome to React!</h2>;
}
We’ll explore components more in the next lecture.
7. Summary
React elements are lightweight, immutable descriptions of UI.
We render them to the DOM using ReactDOM.createRoot() and .render().
JSX is used to write elements in a more readable format.
React automatically updates the DOM when data changes.
Components and Props
(Part of Module 2: React Fundamentals)
Lecture Objectives:
By the end of this lecture, students will be able to:
Understand what React components are.
Create and use functional components.
Pass data into components using props.
Reuse and nest components for modular design.
1. Introduction
React is built around the idea of components.
Components are the building blocks of a React application.
They help you break down the UI into smaller, reusable pieces.
Each component is independent and self-contained,
and it can accept input called props to make it dynamic.
In this lecture, you’ll learn how to:
Create components
Use them in your app
Pass data through props
2. What is a Component?
A component is a JavaScript function or class
that returns a React element (usually written in JSX).
It defines a part of the user interface.
React has two types of components:
Functional Components (modern and preferred)
Class Components (older; still supported)
We’ll focus on functional components, which are simpler and cleaner.
✅ Example of a Functional Component:
function Welcome() {
return <h1>Hello, React!</h1>;
}
You can use this component like a custom HTML tag:
<Welcome />
That’s how React knows to call the Welcome function
and render its output.
3. Reusability with Components
One of the main benefits of using components
is that you can reuse them throughout your application.
For example, if you have a Button component,
you can use it multiple times in different parts of the UI.
This keeps your code modular, maintainable, and scalable.
4. What are Props?
Props stands for “properties”.
They are inputs passed to a component
to make it dynamic and customizable.
Think of props like arguments to a function.
You pass them like attributes in JSX:
<Welcome name="Sumaiyya" />
And receive them in the component like this:
function Welcome(props) {
return <h1>Hello, {props.name}!</h1>;
}
This allows the same component to render different content
based on the props it receives.
5. Props Are Read-Only
Props are immutable.
You can read them inside the component,
but you shouldn’t modify them.
If you need to update or manage data,
you’ll use state, which we’ll cover in a later lecture.
6. Destructuring Props (Optional Enhancement)
Instead of writing props.name,
you can use destructuring for cleaner code:
function Welcome({ name }) {
return <h1>Hello, {name}!</h1>;
}
This is just a JavaScript feature —
totally optional, but widely used in modern React code.
7. Nesting Components
You can compose components together to build complex UIs.
Example:
function App() {
return (
<div>
<Welcome name="Sumaiyya" />
<Welcome name="Ayaan" />
</div>
);
}
Here, the App component renders multiple Welcome components
with different props.
This makes React applications scalable and organized.
8. Summary
Components are the core units of a React app.
They return JSX and can be reused across the app.
Props allow you to pass data into components.
Props are read-only and help make components dynamic.
You can nest components to build a full interface.
Functional vs Class Components
(Part of Module 2: React Fundamentals)
Lecture Objectives:
By the end of this lecture, students will:
Understand the difference between functional and class components.
Know the syntax and structure of both types.
Recognize when to use functional components.
Learn about React Hooks and how they empower functional components.
1. Introduction
React allows us to build UI using components,
and there are two primary ways to define them:
Functional Components
Class Components
Originally, class components were used when you needed state or lifecycle methods,
but with the introduction of React Hooks in version 16.8,
functional components can now do everything class components can — and more.
In this lecture, we’ll compare both styles and help you decide which one to use.
2. Functional Components
A functional component is simply a JavaScript function
that returns JSX.
They are:
Easy to write and understand
Lightweight
More concise
✅ Example:
function Greeting(props) {
return <h1>Hello, {props.name}!</h1>;
}
You can also use destructuring:
function Greeting({ name }) {
return <h1>Hello, {name}!</h1>;
}
Functional components are stateless by default,
but with Hooks, they can manage state and side effects too.
3. Class Components
A class component is a JavaScript class
that extends React.Component
and must include a render() method to return JSX.
They are more verbose and look like this:
✅ Example:
import React, { Component } from 'react';
class Greeting extends Component {
render() {
return <h1>Hello, {this.props.name}!</h1>;
}
}
Class components can also have:
State
Lifecycle methods (like componentDidMount, componentDidUpdate)
However, with Hooks, these can now be used in functional components too.
4. Key Differences
Feature
Functional Component
Class Component
Syntax
Function
Class
Simplicity
Simple and concise
Verbose
this Keyword
Not needed
Required (this.props, this.state)
Hooks Supported
Yes
No (Hooks are only for functions)
Lifecycle Methods
With Hooks (useEffect, etc.)
Built-in (componentDidMount, etc.)
Preferred in React?
✅ Yes (modern approach)
❌ No longer recommended
5. Why Prefer Functional Components?
Easier to write and maintain
No this keyword confusion
Hooks make them just as powerful as class components
Better performance in some cases
More readable code
In modern React development,
functional components are the standard.
Class components are still supported,
but you’ll rarely need them unless working in legacy codebases.
6. React Hooks Overview (Brief Intro)
Hooks let you use state, lifecycle methods, and context
in functional components.
Examples of common Hooks:
useState — for state management
useEffect — for lifecycle behavior
useContext, useRef, useReducer — for advanced needs
We’ll cover these Hooks in detail in later lectures.
7. Summary
Functional components are simpler and more modern.
Class components are older and more verbose.
With Hooks, functional components can handle all logic — including state and lifecycle.
For almost all use cases today, functional components are preferred.
Lecture Objectives:
By the end of this lecture, students will:
Understand how to handle events in React.
Learn the differences between event handling in React and HTML.
Write functions to respond to user actions like clicks and input changes.
Pass event handlers as props to reusable components.
1. Introduction
Just like in plain HTML and JavaScript,
React allows you to respond to user actions — like clicking a button,
typing into an input box, or submitting a form.
This is done using event handling.
In this lecture, you'll learn how to:
Attach events in React,
Create event handler functions,
Pass parameters to event handlers,
And keep your code clean and modular.
2. React Event Handling Basics
In React, events are handled a bit differently compared to plain HTML.
Here’s how they differ:
Feature
HTML
React
Event Name
Lowercase: onclick
CamelCase: onClick
Event Handler
String: "functionName()"
Function: {functionName}
✅ HTML Example:
<button onclick="handleClick()">Click Me</button>
✅ React Example:
<button onClick={handleClick}>Click Me</button>
In React:
We use camelCase event names like onClick, onChange, onSubmit, etc.
We pass a function reference, not a string or function call.
3. Creating an Event Handler Function
An event handler is a simple JavaScript function
that gets called when an event occurs.
Example:
function handleClick() {
alert("Button clicked!");
}
function App() {
return <button onClick={handleClick}>Click Me</button>;
}
When the user clicks the button,
the handleClick function runs and shows an alert.
4. Passing Arguments to Event Handlers
Sometimes you want to pass additional data when handling events.
You can do that using an arrow function:
function handleClick(name) {
alert(`Hello, ${name}!`);
}
function App() {
return <button onClick={() => handleClick("Sumaiyya")}>Greet</button>;
}
Here, we’re passing "Sumaiyya" to the handleClick function
when the button is clicked.
5. Handling Input Events
You can handle input fields using the onChange event.
Example:
function App() {
const handleChange = (event) => {
console.log("Input value:", event.target.value);
};
return <input type="text" onChange={handleChange} />;
}
React gives you access to the event object,
so you can get values, prevent form submission, and more.
6. Preventing Default Behavior
For example, to stop a form from submitting and refreshing the page:
function handleSubmit(event) {
event.preventDefault();
alert("Form submitted!");
}
function App() {
return (
<form onSubmit={handleSubmit}>
<button type="submit">Submit</button>
</form>
);
}
Use event.preventDefault() to stop the default behavior.
7. Passing Event Handlers as Props
In React, you can pass event handlers as props
to reusable components.
Example:
function Button({ onClick, label }) {
return <button onClick={onClick}>{label}</button>;
}
function App() {
const handleClick = () => {
alert("Button clicked from App!");
};
return <Button onClick={handleClick} label="Click Me" />;
}
This makes your components flexible and reusable.
8. Summary
React uses camelCase for event names: onClick, onChange, etc.
Pass functions, not strings, as event handlers.
You can pass arguments using arrow functions.
You can access the event object to get values and prevent default behavior.
Event handlers can also be passed as props for better reusability.
Conditional Rendering in React
Lecture Objectives:
By the end of this lecture, students will be able to:
Understand what conditional rendering is.
Use if-else, ternary operators, and logical && in JSX.
Display different content based on conditions.
Apply conditional rendering inside components to build dynamic interfaces.
1. Introduction
In any application,
you’ll often want to display different UI elements
based on certain conditions.
For example:
Show a welcome message only when a user is logged in.
Display a loading spinner while fetching data.
Hide a button when a form is submitted
This concept is called conditional rendering.
In React, conditional rendering works just like JavaScript —
because JSX is basically JavaScript under the hood.
2. Using If-Else Statements (Outside JSX)
You can use regular if-else statements before the return statement.
✅ Example:
function Greeting({ isLoggedIn }) {
if (isLoggedIn) {
return <h1>Welcome back!</h1>;
} else {
return <h1>Please sign in.</h1>;
}
}
Here, the returned JSX depends on the isLoggedIn prop.
3. Using Ternary Operators (Inline JSX)
You can also use a ternary operator
when you want to write conditions inside JSX.
✅ Example:
function Greeting({ isLoggedIn }) {
return (
<h1>
{isLoggedIn ? "Welcome back!" : "Please sign in."}
</h1>
);
}
This makes the code concise and useful for short conditions.
4. Using Logical AND (&&) for Simple Conditions
If you want to render something only when a condition is true,
you can use the logical AND operator.
✅ Example:
function Notification({ hasMessage }) {
return (
<div>
{hasMessage && <p>You have new messages.</p>}
</div>
);
}
If hasMessage is true, the paragraph is shown.
If it's false, nothing is rendered.
This is great for optional rendering.
5. Avoiding Rendering with Null
Sometimes, you may want to render nothing based on a condition.
In that case, return null:
function Popup({ show }) {
if (!show) return null;
return <div className="popup">This is a popup!</div>;
}
Returning null tells React to render nothing.
6. Multiple Conditions or Content Blocks
For more complex scenarios,
you can use variables and conditions before the return:
function Status({ status }) {
let message;
if (status === "loading") {
message = <p>Loading...</p>;
} else if (status === "success") {
message = <p>Data loaded successfully!</p>;
} else {
message = <p>Something went wrong.</p>;
}
return <div>{message}</div>;
}
This keeps your JSX clean and readable.
7. Summary
Conditional rendering lets you show different UI based on data.
Use:
if-else outside JSX
Ternary condition ? value1 : value2 inside JSX
Logical && for short true-only cases
null to render nothing
It helps you build dynamic, responsive interfaces.
Lecture Title: Lists and Keys in React
In React, rendering lists of data is a common task, whether you are building a to-do list, product catalog, or search results.
To efficiently manage these lists, React uses Lists for rendering and Keys to keep track of each item’s identity.
What are Lists in React?
A List in React is simply an array of data that you map into JSX elements.
You can use JavaScript’s .map() method to loop through data and return components.
Example:
function NameList() {
const names = ["Alice", "Bob", "Charlie"];
return (
<ul>
{names.map((name) => (
<li>{name}</li>
))}
</ul>
);
}
Why Keys are Important
Keys help React identify which items have changed, been added, or removed.
Without keys, React may re-render elements inefficiently.
Keys should be unique among siblings.
Bad Practice (Index as Key for Dynamic Data):
{items.map((item, index) => (
<li key={index}>{item}</li>
))}
Using index as a key can cause unexpected UI behavior when list items change order.
Good Practice (Unique IDs):
{items.map((item) => (
<li key={item.id}>{item.name}</li>
))}
Combining Lists and Keys
Example with Object Data:
function ProductList() {
const products = [
{ id: 1, name: "Laptop" },
{ id: 2, name: "Phone" },
{ id: 3, name: "Tablet" }
];
return (
<ul>
{products.map((product) => (
<li key={product.id}>{product.name}</li>
))}
</ul>
);
}
Best Practices for Lists and Keys
Always use a unique, stable key for each item.
Avoid using array indexes as keys when items can change order.
Keep keys consistent between renders.
Keys don’t have to be globally unique — only unique among siblings.
Common Pitfalls
Forgetting the key prop → React will show a warning.
Using non-unique keys → Can cause incorrect re-renders.
Changing keys unnecessarily → Forces React to destroy and recreate components instead of updating them.
Practical Example: Dynamic List
import { useState } from "react";
function TodoApp() {
const [todos, setTodos] = useState([
{ id: 1, task: "Learn React" },
{ id: 2, task: "Build a project" }
]);
const addTodo = () => {
const newTodo = { id: Date.now(), task: "New Task" };
setTodos([...todos, newTodo]);
};
return (
<div>
<button onClick={addTodo}>Add Task</button>
<ul>
{todos.map((todo) => (
<li key={todo.id}>{todo.task}</li>
))}
</ul>
</div>
);
}
export default TodoApp;
Summary
Lists: Render data using .map().
Keys: Help React identify elements for efficient updates.
Use unique IDs for keys instead of indexes for dynamic lists.
Following best practices ensures better performance and fewer bugs.
Forms and Controlled Components (with TypeScript)
Lecture Introduction
In this lecture, we’ll learn how to handle forms in React using controlled components, and how to strongly type them with TypeScript.
You’ll see how React takes control of form inputs, making it easier to validate data, show feedback, and keep everything predictable.
What is a Controlled Component?
In a normal HTML form, the DOM manages input values.
In React, a controlled component means the input’s value is stored in React state.
Every keystroke updates React state, and React re-renders the input.
This creates a single source of truth in the component state.
Example 1: A Simple Controlled Input
import React, { useState } from "react";
export default function NameForm() {
const [name, setName] = useState<string>("");
const handleChange = (e: React.ChangeEvent<HTMLInputElement>) => {
setName(e.target.value);
};
const handleSubmit = (e: React.FormEvent<HTMLFormElement>) => {
e.preventDefault();
alert(`Hello, ${name || "Anonymous"}!`);
};
return (
<form onSubmit={handleSubmit}>
<input
type="text"
value={name}
onChange={handleChange}
placeholder="Enter your name"
/>
<button type="submit">Submit</button>
</form>
);
}
Explanation
useState<string>("") ensures the state is always a string.
React.ChangeEvent<HTMLInputElement> is the correct type for input change events.
The value of the input comes from state, not the DOM.
Example 2: Multiple Inputs in One Form
import React, { useState } from "react";
type FormData = {
email: string;
password: string;
};
export default function LoginForm() {
const [form, setForm] = useState<FormData>({ email: "", password: "" });
const handleChange = (e: React.ChangeEvent<HTMLInputElement>) => {
const { name, value } = e.target;
setForm((prev) => ({ ...prev, [name]: value }));
};
const handleSubmit = (e: React.FormEvent<HTMLFormElement>) => {
e.preventDefault();
console.log("Submitted:", form);
};
return (
<form onSubmit={handleSubmit}>
<input
type="email"
name="email"
value={form.email}
onChange={handleChange}
placeholder="Email"
/>
<input
type="password"
name="password"
value={form.password}
onChange={handleChange}
placeholder="Password"
/>
<button type="submit">Login</button>
</form>
);
}
Explanation
The FormData type ensures state always matches the correct structure.
setForm((prev) => … ) spreads old values and updates only the changed field.
A single generic change handler works for all inputs.
Example 3: Checkboxes, Radio Buttons, and Select Dropdowns
import React, { useState } from "react";
type Preferences = {
subscribed: boolean;
role: "student" | "instructor";
theme: "light" | "dark";
};
export default function PreferencesForm() {
const [prefs, setPrefs] = useState<Preferences>({
subscribed: false,
role: "student",
theme: "light"
});
const handleCheckbox = (e: React.ChangeEvent<HTMLInputElement>) => {
setPrefs((prev) => ({ ...prev, subscribed: e.target.checked }));
};
const handleRadio = (e: React.ChangeEvent<HTMLInputElement>) => {
setPrefs((prev) => ({ ...prev, role: e.target.value as Preferences["role"] }));
};
const handleSelect = (e: React.ChangeEvent<HTMLSelectElement>) => {
setPrefs((prev) => ({ ...prev, theme: e.target.value as Preferences["theme"] }));
};
const handleSubmit = (e: React.FormEvent<HTMLFormElement>) => {
e.preventDefault();
console.log("Preferences:", prefs);
};
return (
<form onSubmit={handleSubmit}>
<label>
<input
type="checkbox"
checked={prefs.subscribed}
onChange={handleCheckbox}
/>
Subscribe to newsletter
</label>
<label>
<input
type="radio"
value="student"
checked={prefs.role === "student"}
onChange={handleRadio}
/>
Student
</label>
<label>
<input
type="radio"
value="instructor"
checked={prefs.role === "instructor"}
onChange={handleRadio}
/>
Instructor
</label>
<select value={prefs.theme} onChange={handleSelect}>
<option value="light">Light Theme</option>
<option value="dark">Dark Theme</option>
</select>
<button type="submit">Save</button>
</form>
);
}
Explanation
checked is used for checkboxes and radios.
value is used for dropdowns.
TypeScript unions ("student" | "instructor") keep values type-safe.
Example 4: Adding Validation
import React, { useState } from "react";
type RegisterData = {
email: string;
password: string;
};
type Errors = Partial<Record<keyof RegisterData, string>>;
export default function RegisterForm() {
const [data, setData] = useState<RegisterData>({ email: "", password: "" });
const [errors, setErrors] = useState<Errors>({});
const handleChange = (e: React.ChangeEvent<HTMLInputElement>) => {
setData((prev) => ({ ...prev, [e.target.name]: e.target.value }));
};
const validate = (): Errors => {
const errs: Errors = {};
if (!data.email.includes("@")) errs.email = "Invalid email";
if (data.password.length < 6) errs.password = "At least 6 characters required";
return errs;
};
const handleSubmit = (e: React.FormEvent<HTMLFormElement>) => {
e.preventDefault();
const errs = validate();
if (Object.keys(errs).length) {
setErrors(errs);
} else {
console.log("Registered:", data);
setErrors({});
}
};
return (
<form onSubmit={handleSubmit}>
<input
name="email"
value={data.email}
onChange={handleChange}
placeholder="Email"
/>
{errors.email && <p style={{color:"red"}}>{errors.email}</p>}
<input
type="password"
name="password"
value={data.password}
onChange={handleChange}
placeholder="Password"
/>
{errors.password && <p style={{color:"red"}}>{errors.password}</p>}
<button type="submit">Register</button>
</form>
);
}
Explanation
Errors is typed as Partial<Record<…>>, so only invalid fields need messages.
Validation runs before submission.
Error messages show dynamically.
Key Takeaways
Controlled components let React manage input values, making them predictable and debuggable.
Always use proper event types in TypeScript (React.ChangeEvent<HTMLInputElement>, React.FormEvent<HTMLFormElement>).
Define types for form data to avoid bugs.
Validation becomes straightforward when all values are stored in state.
Understanding the useState() Hook (with TypeScript)
Lecture Introduction
In this lecture, we’ll dive into one of the most commonly used React hooks: useState().
This hook allows us to add state to functional components. With TypeScript, we can strongly type our state values, making our applications safer and easier to maintain.
What is useState()?
React’s useState hook lets you store values that persist between renders.
State changes trigger re-renders, updating the UI automatically.
Syntax:
const [state, setState] = useState<type>(initialValue);
state → current value
setState → function to update the value
<type> → optional TypeScript generic to define the state type
Example 1: Basic Counter (Number State)
import React, { useState } from "react";
export default function Counter() {
const [count, setCount] = useState<number>(0);
const increment = () => setCount((prev) => prev + 1);
const decrement = () => setCount((prev) => prev - 1);
return (
<div>
<p>Count: {count}</p>
<button onClick={increment}>+</button>
<button onClick={decrement}>-</button>
</div>
);
}
Explanation
useState<number>(0) → state variable count is typed as a number, starting at 0.
increment and decrement functions update state using setCount.
When count changes, React re-renders and displays the new value.
Example 2: String State (Input Field)
import React, { useState } from "react";
export default function NameForm() {
const [name, setName] = useState<string>("");
const handleChange = (e: React.ChangeEvent<HTMLInputElement>) => {
setName(e.target.value);
};
return (
<div>
<input
type="text"
value={name}
onChange={handleChange}
placeholder="Enter your name"
/>
<p>Hello, {name || "stranger"}!</p>
</div>
);
}
Explanation
useState<string>("") → initializes state as an empty string.
handleChange updates the state every time the user types.
The UI updates instantly with the typed name.
Example 3: Boolean State (Toggling UI)
import React, { useState } from "react";
export default function ToggleMessage() {
const [visible, setVisible] = useState<boolean>(false);
const toggle = () => setVisible((prev) => !prev);
return (
<div>
<button onClick={toggle}>
{visible ? "Hide" : "Show"} Message
</button>
{visible && <p>This is a toggleable message!</p>}
</div>
);
}
Explanation
useState<boolean>(false) → state starts as false.
The toggle function flips the value from true to false.
Conditional rendering ({visible && ...}) shows or hides the message.
Example 4: Complex State (Objects)
import React, { useState } from "react";
type User = {
name: string;
age: number;
};
export default function UserProfile() {
const [user, setUser] = useState<User>({ name: "", age: 0 });
const updateName = (e: React.ChangeEvent<HTMLInputElement>) => {
setUser((prev) => ({ ...prev, name: e.target.value }));
};
const updateAge = (e: React.ChangeEvent<HTMLInputElement>) => {
setUser((prev) => ({ ...prev, age: Number(e.target.value) }));
};
return (
<div>
<input
type="text"
value={user.name}
onChange={updateName}
placeholder="Enter name"
/>
<input
type="number"
value={user.age}
onChange={updateAge}
placeholder="Enter age"
/>
<p>{user.name ? `${user.name} is ${user.age} years old.` : "No user yet."}</p>
</div>
);
}
Explanation
useState<User> → ensures our state object always has a name string and an age number.
The spread operator ...prev is used to update only one field at a time.
UI updates reflect both fields immediately.
Best Practices
Always type your state in TypeScript for better safety.
Use setState((prev) => … ) when updating based on the previous value.
Keep state minimal and avoid nesting deeply.
For complex forms, consider splitting state into multiple useState calls or using useReducer.
Summary
useState() adds state to functional components.
You can store numbers, strings, booleans, objects, or arrays.
TypeScript generics help ensure correctness.
State changes trigger re-renders, keeping UI in sync with data.
Lifting State Up (with TypeScript)
Lecture Goals
Understand why and when to lift state up
Learn the data flow pattern: child ➜ parent via callbacks
Implement shared state in a parent and prop-drill values + handlers to children
Avoid common pitfalls (duplicated state, stale derived values)
See a complete Celsius ↔ Fahrenheit converter using lifted state
Why “Lift State Up”?
When two or more components need to share or synchronize data, keeping separate copies of state in each child causes bugs (drift, double updates).
Solution: Move the state to their closest common ancestor and pass:
Data down as props
Intent up via callback props
This gives you a single source of truth and predictable rendering.
Core Pattern (Minimal Example)
Parent holds state, passes value + onChange to children
import React, { useState } from "react";
type ChildProps = {
value: string;
onChange: (next: string) => void;
};
function ChildInput({ value, onChange }: ChildProps) {
return (
<input
value={value}
onChange={(e) => onChange(e.target.value)}
placeholder="Type something"
/>
);
}
export default function Parent() {
const [text, setText] = useState<string>("");
return (
<div>
<ChildInput value={text} onChange={setText} />
<p>Mirror: {text}</p>
</div>
);
}
What’s happening
Parent owns text state.
ChildInput is controlled by value and reports user edits via onChange.
Parent updates its state and re-renders all dependents consistently.
Classic Case Study: Temperature Converter
Goal: Two inputs (Celsius and Fahrenheit) should always stay in sync.
If each input kept its own state, they would get out of sync. We lift the state to the parent.
Utility functions (pure, testable)
export const toC = (f: number) => (f - 32) * (5 / 9);
export const toF = (c: number) => c * (9 / 5) + 32;
export function tryParseNumber(s: string): number | null {
if (s.trim() === "") return null;
const n = Number(s);
return Number.isFinite(n) ? n : null;
}
TemperatureInput (reusable child)
import React from "react";
type Scale = "c" | "f";
const scaleLabels: Record<Scale, string> = { c: "Celsius", f: "Fahrenheit" };
type TemperatureInputProps = {
scale: Scale;
value: string; // displayed value (controlled)
onChange: (next: string) => void; // report user edits
};
export function TemperatureInput({ scale, value, onChange }: TemperatureInputProps) {
return (
<div>
<label>
{scaleLabels[scale]}:
<input
value={value}
onChange={(e) => onChange(e.target.value)}
placeholder={`Enter ${scaleLabels[scale]}`}
/>
</label>
</div>
);
}
Parent owns the single source of truth
import React, { useState } from "react";
import { TemperatureInput } from "./TemperatureInput";
import { toC, toF, tryParseNumber } from "./temperature-utils";
type Scale = "c" | "f";
export default function TemperatureConverter() {
// Single source of truth: last edited scale + raw text value
const [scale, setScale] = useState<Scale>("c");
const [value, setValue] = useState<string>("");
const handleCelsiusChange = (next: string) => {
setScale("c");
setValue(next);
};
const handleFahrenheitChange = (next: string) => {
setScale("f");
setValue(next);
};
// Derive the sibling value on render (do not store duplicates)
const celsiusText =
scale === "c"
? value
: (() => {
const n = tryParseNumber(value);
return n === null ? "" : String(Math.round(toC(n)));
})();
const fahrenheitText =
scale === "f"
? value
: (() => {
const n = tryParseNumber(value);
return n === null ? "" : String(Math.round(toF(n)));
})();
// Optional: additional derived UI (e.g., water boil check)
const cNum = tryParseNumber(celsiusText);
const verdict =
cNum === null ? "" : cNum >= 100 ? "Water would boil." : "Water would not boil.";
return (
<div>
<h3>Temperature Converter</h3>
<TemperatureInput scale="c" value={celsiusText} onChange={handleCelsiusChange} />
<TemperatureInput scale="f" value={fahrenheitText} onChange={handleFahrenheitChange} />
<p>{verdict}</p>
</div>
);
}
Key ideas
Single source of truth: (scale, value) tracked by parent.
No duplicate state: sibling value is derived at render time.
Children are dumb/presentational: they receive value and report onChange.
Multi-Child Form: Siblings Sharing State
Example: Filters + List
import React, { useMemo, useState } from "react";
type Product = { id: number; name: string; price: number; inStock: boolean };
const PRODUCTS: Product[] = [
{ id: 1, name: "Keyboard", price: 1999, inStock: true },
{ id: 2, name: "Mouse", price: 999, inStock: false },
{ id: 3, name: "Monitor", price: 9999, inStock: true },
];
type FilterState = {
query: string;
onlyInStock: boolean;
maxPrice: number | "";
};
function Filters({
value,
onChange,
}: {
value: FilterState;
onChange: (next: FilterState) => void;
}) {
const update = <K extends keyof FilterState>(key: K, next: FilterState[K]) =>
onChange({ ...value, [key]: next });
return (
<div>
<input
placeholder="Search…"
value={value.query}
onChange={(e) => update("query", e.target.value)}
/>
<label>
<input
type="checkbox"
checked={value.onlyInStock}
onChange={(e) => update("onlyInStock", e.target.checked)}
/>
Only in stock
</label>
<input
type="number"
placeholder="Max price"
value={value.maxPrice}
onChange={(e) =>
update("maxPrice", e.target.value === "" ? "" : Number(e.target.value))
}
/>
</div>
);
}
function ProductList({ items }: { items: Product[] }) {
if (!items.length) return <p>No results.</p>;
return (
<ul>
{items.map((p) => (
<li key={p.id}>
{p.name} — ₹{p.price} {p.inStock ? "(In stock)" : "(Out of stock)"}
</li>
))}
</ul>
);
}
export default function Catalog() {
const [filters, setFilters] = useState<FilterState>({
query: "",
onlyInStock: false,
maxPrice: "",
});
const filtered = useMemo(() => {
return PRODUCTS.filter((p) => {
if (filters.onlyInStock && !p.inStock) return false;
if (filters.maxPrice !== "" && p.price > filters.maxPrice) return false;
if (filters.query && !p.name.toLowerCase().includes(filters.query.toLowerCase()))
return false;
return true;
});
}, [filters]);
return (
<div>
<h3>Catalog</h3>
<Filters value={filters} onChange={setFilters} />
<ProductList items={filtered} />
</div>
);
}
What to notice
Parent (Catalog) owns all filter state.
Filters and ProductList are siblings that stay in sync through parent state.
Derived data (filtered) computed with useMemo from the single source of truth.
Best Practices & Pitfalls
Do
Lift state to the nearest common ancestor when multiple children depend on it.
Keep derived values out of state; compute them from the source state during render (useMemo if expensive).
Use precise prop types and callback types:
type OnChange<T> = (next: T) => void;
Avoid
Duplicated state in siblings (causes divergence).
Two-way binding loops (ensure a single owner for the value).
Over-lifting: if only one child needs it, keep state local.
Deep prop drilling across many layers; consider Context when many distant components need the same state.
When Not to Lift (Alternatives)
Context API: shared app-wide prefs (theme, auth user).
State libraries (Zustand, Redux) when many modules need to read/write.
Local state: if the data is only used within one component.
In this lesson, you’ll get a clear, practical understanding of the useEffect Hook in React — one of the most essential and commonly misunderstood hooks. You will learn:
when and how useEffect runs after rendering
how the dependency array controls effect execution
how to avoid common mistakes like infinite loops or unnecessary re-runs
how to correctly use cleanup functions to avoid memory leaks
best practices for working with side effects in functional components
This video emphasizes real use cases and pitfalls every junior developer should avoid, helping you write better, bug-free React code with confidence.
Course Description:
Are you ready to build modern, scalable, and fast web applications with one of the most in-demand frontend libraries? Whether you're a beginner in web development or an experienced JavaScript developer looking to advance your skills, this comprehensive React JS course is designed to make you proficient in building real-world applications using modern React practices.
In this course, you'll go from the absolute basics of React to mastering advanced concepts like custom hooks, state management, routing, and performance optimization. You’ll learn by building interactive UI components, handling user inputs, integrating APIs, and deploying your app for production.
What You’ll Learn:
Understand the core concepts of React: components, props, state, and lifecycle
Build and structure single-page applications (SPA) using React Router
Manage application state using Context API and Redux Toolkit
Work with modern features like Hooks (useState, useEffect, useReducer, etc.)
Optimize performance with memoization and lazy loading
Build reusable and maintainable UI components
Integrate RESTful APIs using Axios and handle async data
Style your applications with CSS Modules, Tailwind CSS, and Styled Components
Build and deploy a complete full-featured project from scratch
Bonus: Introduction to Next.js for server-side rendering (optional module)
Who This Course Is For:
Developers new to React or frontend frameworks
JavaScript developers looking to upgrade to modern frontend stacks
Backend developers or full-stack engineers wanting to build dynamic UIs
Students or professionals preparing for frontend interviews
Tools & Technologies Covered:
React 18+
JavaScript (ES6+)
Redux Toolkit
React Router
Axios
Tailwind CSS / Styled Components
Next.js (optional)
Vite/Webpack, Git, and deployment via Netlify or Vercel
Projects You'll Build:
Dynamic Todo App with CRUD
Weather Forecast Dashboard with API
Responsive Blog Platform with Routing and Search
Full E-commerce Frontend with Cart, Auth, and Checkout