Master React fundamentals including JSX syntax, functional components, props, and event handling. Build your first interactive React components with modern patterns.
React is a JavaScript library for building user interfaces, created by Facebook and now maintained by Meta. It revolutionized front-end development by introducing a component-based approach that makes complex UIs easier to build, maintain, and scale.
At its core, React is about thinking in components - independent, reusable pieces of code that represent parts of your user interface. Instead of manipulating the DOM directly, you describe what your UI should look like for any given state, and React takes care of updating the DOM efficiently.
React's power comes from its simplicity: components are just JavaScript functions that return JSX (a syntax extension that looks like HTML). This makes React code predictable, debuggable, and easy to reason about. Whether you're building a simple blog or a complex application like Facebook or Netflix, React's patterns scale beautifully.
In this lesson, you'll learn React from the ground up, understanding not just the syntax but the philosophy behind component-based development that has become the standard for modern web applications.
React is built around the concept of components - independent, reusable pieces of code that represent parts of a user interface. Understanding this philosophy is crucial to mastering React.
What is React?
React is a JavaScript library for building user interfaces. It's:
The Component Mental Model:
Think of components as custom HTML elements with superpowers:
1// Traditional HTML
2<button>Click me</button>
3
4// React Component
5<CustomButton onClick={handleClick} variant="primary">
6 Click me
7</CustomButton>Core React Concepts:
1. Components Are Functions
In modern React, components are just JavaScript functions that return JSX:
1function Welcome() {
2 return <h1>Hello, World!</h1>;
3}
4
5// Arrow function syntax
6const Welcome = () => {
7 return <h1>Hello, World!</h1>;
8};2. JSX Describes the UI
JSX looks like HTML but is actually JavaScript that gets transformed:
1// JSX
2const element = <h1>Hello, React!</h1>;
3
4// Transforms to
5const element = React.createElement('h1', null, 'Hello, React!');3. Props Make Components Reusable
Props (properties) are how you pass data to components:
1function Greeting({ name }) {
2 return <h1>Hello, {name}!</h1>;
3}
4
5// Usage
6<Greeting name="Alice" />
7<Greeting name="Bob" />4. Composition Over Inheritance
React favors composition - building complex components by combining simpler ones:
1function App() {
2 return (
3 <div>
4 <Header />
5 <MainContent />
6 <Footer />
7 </div>
8 );
9}React's Virtual DOM:
React uses a Virtual DOM - a JavaScript representation of the actual DOM:
Benefits of React's Approach:
React Ecosystem:
React is just the core library. The ecosystem includes:
Modern React Features:
React vs Other Approaches:
1// jQuery (imperative)
2$('#myButton').click(function() {
3 $('#counter').text(parseInt($('#counter').text()) + 1);
4});
5
6// React (declarative)
7function Counter() {
8 const [count, setCount] = useState(0);
9
10 return (
11 <div>
12 <span id="counter">{count}</span>
13 <button onClick={() => setCount(count + 1)}>
14 Increment
15 </button>
16 </div>
17 );
18}Why React Won:
Getting Started with React:
1# Create a new React app
2npx create-react-app my-app
3cd my-app
4npm startReact's component-based approach fundamentally changed how we think about building user interfaces, making it the foundation for modern front-end development.
JSX (JavaScript XML) is a syntax extension for JavaScript that allows you to write HTML-like code directly in your JavaScript files. It's one of React's most distinctive features and makes component development intuitive and powerful.
What is JSX?
JSX lets you write what looks like HTML directly in JavaScript:
1const element = <h1>Hello, JSX!</h1>;Under the hood, JSX is transformed into regular JavaScript function calls:
1// JSX
2const element = <h1 className="greeting">Hello, world!</h1>;
3
4// Compiled JavaScript
5const element = React.createElement(
6 'h1',
7 { className: 'greeting' },
8 'Hello, world!'
9);JSX Rules and Syntax:
1. Single Root Element
JSX expressions must have one parent element:
1// ❌ Wrong - multiple root elements
2return (
3 <h1>Title</h1>
4 <p>Paragraph</p>
5);
6
7// ✅ Correct - single root element
8return (
9 <div>
10 <h1>Title</h1>
11 <p>Paragraph</p>
12 </div>
13);
14
15// ✅ Alternative - React Fragment
16return (
17 <>
18 <h1>Title</h1>
19 <p>Paragraph</p>
20 </>
21);2. JavaScript Expressions in JSX
Use curly braces {} to embed JavaScript expressions:
1function Welcome({ name, age }) {
2 const isAdult = age >= 18;
3
4 return (
5 <div>
6 <h1>Hello, {name}!</h1>
7 <p>You are {age} years old</p>
8 <p>Status: {isAdult ? 'Adult' : 'Minor'}</p>
9 <p>Next year you'll be {age + 1}</p>
10 </div>
11 );
12}3. Attributes in JSX
JSX attributes use camelCase and some have different names:
1// HTML attributes vs JSX props
2<div
3 className="container" // class -> className
4 htmlFor="input-id" // for -> htmlFor
5 onClick={handleClick} // onclick -> onClick
6 tabIndex={0} // tabindex -> tabIndex
7 style={'{'{{ // style object, not string
8 backgroundColor: 'blue',
9 fontSize: '16px' }}'}}
10>
11 Content
12</div>4. Self-Closing Tags
All tags must be properly closed:
1// ❌ Wrong
2<img src="photo.jpg">
3<input type="text">
4
5// ✅ Correct
6<img src="photo.jpg" />
7<input type="text" />5. JSX Comments
Use JavaScript comments inside JSX:
1return (
2 <div>
3 {/* This is a JSX comment */}
4 <h1>Title</h1>
5 {/*
6 Multi-line JSX comment
7 spanning multiple lines
8 */}
9 <p>Content</p>
10 </div>
11);Dynamic Content and Conditional Rendering:
Conditional Rendering with Ternary Operator:
1function UserStatus({ isLoggedIn, username }) {
2 return (
3 <div>
4 {isLoggedIn ? (
5 <p>Welcome back, {username}!</p>
6 ) : (
7 <p>Please log in</p>
8 )}
9 </div>
10 );
11}Conditional Rendering with Logical AND:
1function Notification({ hasNewMessages, messageCount }) {
2 return (
3 <div>
4 <h1>Dashboard</h1>
5 {hasNewMessages && (
6 <div className="notification">
7 You have {messageCount} new messages!
8 </div>
9 )}
10 </div>
11 );
12}Rendering Lists:
1function TodoList({ todos }) {
2 return (
3 <ul>
4 {todos.map(todo => (
5 <li key={todo.id}>
6 {todo.text}
7 </li>
8 ))}
9 </ul>
10 );
11}Advanced JSX Patterns:
Spread Attributes:
1function Button({ children, ...props }) {
2 return (
3 <button
4 className="btn"
5 {...props} // Spreads all other props
6 >
7 {children}
8 </button>
9 );
10}
11
12// Usage
13<Button onClick={handleClick} disabled={true}>
14 Click me
15</Button>JSX as Variables and Function Returns:
1function App() {
2 const header = <h1>Welcome to React</h1>;
3
4 const renderContent = () => {
5 return <p>This content is returned from a function</p>;
6 };
7
8 return (
9 <div>
10 {header}
11 {renderContent()}
12 </div>
13 );
14}JSX with Complex Expressions:
1function ShoppingCart({ items }) {
2 const total = items.reduce((sum, item) => sum + item.price, 0);
3
4 return (
5 <div>
6 <h2>Shopping Cart</h2>
7 {items.length === 0 ? (
8 <p>Your cart is empty</p>
9 ) : (
10 <>
11 <ul>
12 {items.map(item => (
13 <li key={item.id}>
14 {item.name} - ${item.price.toFixed(2)}
15 </li>
16 ))}
17 </ul>
18 <div className="total">
19 Total: ${total.toFixed(2)}
20 </div>
21 </>
22 )}
23 </div>
24 );
25}JSX Best Practices:
1. Keep JSX Readable:
1// ❌ Hard to read
2return <div className="container"><h1 className="title">Hello</h1><p className="content">{user.name} is {user.age} years old and {user.isActive ? 'active' : 'inactive'}</p></div>;
3
4// ✅ Easy to read
5return (
6 <div className="container">
7 <h1 className="title">Hello</h1>
8 <p className="content">
9 {user.name} is {user.age} years old and{' '}
10 {user.isActive ? 'active' : 'inactive'}
11 </p>
12 </div>
13);2. Extract Complex Logic:
1function UserCard({ user }) {
2 const getUserStatus = (user) => {
3 if (!user.isActive) return 'Inactive';
4 if (user.isPremium) return 'Premium Member';
5 return 'Active Member';
6 };
7
8 const statusClass = user.isActive ? 'active' : 'inactive';
9
10 return (
11 <div className={`user-card ${statusClass}`}>
12 <h3>{user.name}</h3>
13 <p>Status: {getUserStatus(user)}</p>
14 </div>
15 );
16}3. Use Fragments to Avoid Extra DOM Nodes:
1// ❌ Creates unnecessary div
2return (
3 <div>
4 <h1>Title</h1>
5 <p>Content</p>
6 </div>
7);
8
9// ✅ No extra DOM node
10return (
11 <>
12 <h1>Title</h1>
13 <p>Content</p>
14 </>
15);JSX and Accessibility:
1function AccessibleForm() {
2 return (
3 <form>
4 <label htmlFor="email">Email:</label>
5 <input
6 id="email"
7 type="email"
8 aria-describedby="email-help"
9 required
10 />
11 <div id="email-help">
12 We'll never share your email with anyone else.
13 </div>
14 </form>
15 );
16}JSX makes React components readable and intuitive while providing the full power of JavaScript for dynamic content and complex UI logic.
Functional components are the modern way to create React components. They're JavaScript functions that return JSX, making them simple, predictable, and easy to test. With the introduction of React Hooks, functional components can do everything class components can do and more.
What are Functional Components?
Functional components are JavaScript functions that take props as an argument and return JSX:
1// Basic functional component
2function Welcome() {
3 return <h1>Hello, World!</h1>;
4}
5
6// Arrow function syntax
7const Welcome = () => {
8 return <h1>Hello, World!</h1>;
9};
10
11// Implicit return for simple components
12const Welcome = () => <h1>Hello, World!</h1>;Component Structure and Naming:
Naming Conventions:
1// ✅ Good component names
2function UserProfile() { }
3function ShoppingCartItem() { }
4function NavigationMenu() { }
5
6// ❌ Poor component names
7function component() { } // lowercase
8function Thing() { } // too generic
9function div() { } // conflicts with HTMLFile Organization:
1// UserProfile.jsx or UserProfile.js
2import React from 'react';
3
4function UserProfile({ user }) {
5 return (
6 <div className="user-profile">
7 <h2>{user.name}</h2>
8 <p>{user.email}</p>
9 </div>
10 );
11}
12
13export default UserProfile;Component Props: Passing Data Down
Basic Props Usage:
1function Greeting({ name, age }) {
2 return (
3 <div>
4 <h1>Hello, {name}!</h1>
5 <p>You are {age} years old.</p>
6 </div>
7 );
8}
9
10// Usage
11<Greeting name="Alice" age={25} />Props Destructuring:
1// ✅ Destructured props (recommended)
2function UserCard({ name, email, avatar, isOnline }) {
3 return (
4 <div className="user-card">
5 <img src={avatar} alt={name} />
6 <h3>{name}</h3>
7 <p>{email}</p>
8 <span className={isOnline ? 'online' : 'offline'}>
9 {isOnline ? '🟢 Online' : '⚫ Offline'}
10 </span>
11 </div>
12 );
13}
14
15// ❌ Non-destructured props (verbose)
16function UserCard(props) {
17 return (
18 <div className="user-card">
19 <img src={props.avatar} alt={props.name} />
20 <h3>{props.name}</h3>
21 <p>{props.email}</p>
22 </div>
23 );
24}Default Props:
1function Button({ text, variant = 'primary', size = 'medium', disabled = false }) {
2 return (
3 <button
4 className={`btn btn-${variant} btn-${size}`}
5 disabled={disabled}
6 >
7 {text}
8 </button>
9 );
10}
11
12// Usage - missing props use defaults
13<Button text="Click me" />
14<Button text="Save" variant="success" size="large" />Props Validation with PropTypes:
1import PropTypes from 'prop-types';
2
3function ProductCard({ name, price, description, inStock }) {
4 return (
5 <div className="product-card">
6 <h3>{name}</h3>
7 <p className="price">${price.toFixed(2)}</p>
8 <p>{description}</p>
9 {inStock ? (
10 <button>Add to Cart</button>
11 ) : (
12 <button disabled>Out of Stock</button>
13 )}
14 </div>
15 );
16}
17
18ProductCard.propTypes = {
19 name: PropTypes.string.isRequired,
20 price: PropTypes.number.isRequired,
21 description: PropTypes.string,
22 inStock: PropTypes.bool
23};
24
25ProductCard.defaultProps = {
26 description: 'No description available',
27 inStock: true
28};Component Composition Patterns:
Children Prop:
1function Card({ title, children }) {
2 return (
3 <div className="card">
4 <div className="card-header">
5 <h2>{title}</h2>
6 </div>
7 <div className="card-body">
8 {children}
9 </div>
10 </div>
11 );
12}
13
14// Usage
15<Card title="User Settings">
16 <p>Manage your account settings</p>
17 <button>Save Changes</button>
18</Card>Render Props Pattern:
1function DataFetcher({ render, url }) {
2 const [data, setData] = useState(null);
3 const [loading, setLoading] = useState(true);
4
5 useEffect(() => {
6 fetch(url)
7 .then(response => response.json())
8 .then(data => {
9 setData(data);
10 setLoading(false);
11 });
12 }, [url]);
13
14 return render({ data, loading });
15}
16
17// Usage
18<DataFetcher
19 url="/api/users"
20 render={({ data, loading }) => (
21 loading ? <div>Loading...</div> : <UserList users={data} />
22 )}
23/>Functional Component with Hooks:
1import React, { useState, useEffect } from 'react';
2
3function Counter({ initialCount = 0, step = 1 }) {
4 const [count, setCount] = useState(initialCount);
5
6 // Effect hook for side effects
7 useEffect(() => {
8 document.title = `Count: ${count}`;
9 }, [count]);
10
11 const increment = () => setCount(count + step);
12 const decrement = () => setCount(count - step);
13 const reset = () => setCount(initialCount);
14
15 return (
16 <div className="counter">
17 <h2>Counter: {count}</h2>
18 <div className="buttons">
19 <button onClick={decrement}>-{step}</button>
20 <button onClick={reset}>Reset</button>
21 <button onClick={increment}>+{step}</button>
22 </div>
23 </div>
24 );
25}Component Organization Patterns:
Presentational vs Container Components:
1// Presentational component - focuses on how things look
2function UserList({ users, onUserSelect }) {
3 return (
4 <ul className="user-list">
5 {users.map(user => (
6 <li key={user.id} onClick={() => onUserSelect(user)}>
7 {user.name}
8 </li>
9 ))}
10 </ul>
11 );
12}
13
14// Container component - focuses on how things work
15function UserListContainer() {
16 const [users, setUsers] = useState([]);
17 const [selectedUser, setSelectedUser] = useState(null);
18
19 useEffect(() => {
20 fetchUsers().then(setUsers);
21 }, []);
22
23 const handleUserSelect = (user) => {
24 setSelectedUser(user);
25 };
26
27 return (
28 <div>
29 <UserList users={users} onUserSelect={handleUserSelect} />
30 {selectedUser && <UserDetail user={selectedUser} />}
31 </div>
32 );
33}Higher-Order Components (HOCs):
1// HOC for adding loading state
2function withLoading(WrappedComponent) {
3 return function WithLoadingComponent({ isLoading, ...props }) {
4 if (isLoading) {
5 return <div>Loading...</div>;
6 }
7 return <WrappedComponent {...props} />;
8 };
9}
10
11// Usage
12const UserListWithLoading = withLoading(UserList);
13
14<UserListWithLoading
15 users={users}
16 isLoading={loading}
17 onUserSelect={handleSelect}
18/>Best Practices for Functional Components:
1. Keep Components Small and Focused:
1// ❌ Too many responsibilities
2function UserDashboard({ userId }) {
3 // ... lots of state and logic
4 return (
5 <div>
6 {/* Tons of JSX */}
7 </div>
8 );
9}
10
11// ✅ Broken into smaller components
12function UserDashboard({ userId }) {
13 return (
14 <div>
15 <UserProfile userId={userId} />
16 <UserStats userId={userId} />
17 <UserActivity userId={userId} />
18 </div>
19 );
20}2. Use Descriptive Props:
1// ❌ Unclear props
2<Modal show={true} size="lg" />
3
4// ✅ Clear props
5<Modal isVisible={true} size="large" />3. Extract Custom Hooks for Logic:
1// Custom hook for form handling
2function useForm(initialValues) {
3 const [values, setValues] = useState(initialValues);
4
5 const handleChange = (event) => {
6 setValues({
7 ...values,
8 [event.target.name]: event.target.value
9 });
10 };
11
12 return [values, handleChange];
13}
14
15// Component uses the custom hook
16function ContactForm() {
17 const [formData, handleInputChange] = useForm({
18 name: '',
19 email: '',
20 message: ''
21 });
22
23 return (
24 <form>
25 <input
26 name="name"
27 value={formData.name}
28 onChange={handleInputChange}
29 />
30 {/* ... */}
31 </form>
32 );
33}Functional components with hooks represent the modern way to write React. They're simpler than class components, easier to test, and provide better performance optimization opportunities.
Props (properties) are how React components communicate with each other. They allow you to pass data from parent to child components, making your components reusable and flexible. Component composition is the practice of combining components to create more complex UIs.
Understanding Props:
Props are read-only data passed from parent to child components. Think of props as function parameters - they provide the input your component needs to render correctly.
1// Parent component passing props
2function App() {
3 const user = {
4 name: 'Alice Johnson',
5 email: '[email protected]',
6 avatar: '/avatars/alice.jpg',
7 isOnline: true
8 };
9
10 return (
11 <div>
12 <UserProfile
13 name={user.name}
14 email={user.email}
15 avatar={user.avatar}
16 isOnline={user.isOnline}
17 />
18 </div>
19 );
20}
21
22// Child component receiving props
23function UserProfile({ name, email, avatar, isOnline }) {
24 return (
25 <div className="user-profile">
26 <img src={avatar} alt={name} />
27 <h2>{name}</h2>
28 <p>{email}</p>
29 <span className={isOnline ? 'status-online' : 'status-offline'}>
30 {isOnline ? 'Online' : 'Offline'}
31 </span>
32 </div>
33 );
34}Props Are Immutable:
Props are read-only within a component. You cannot modify props directly:
1function Counter({ count }) {
2 // ❌ Wrong - cannot modify props
3 count = count + 1;
4
5 // ❌ Wrong - cannot modify props
6 count += 1;
7
8 return <div>Count: {count}</div>;
9}
10
11// ✅ Correct - use state for changes
12function Counter({ initialCount }) {
13 const [count, setCount] = useState(initialCount);
14
15 return (
16 <div>
17 Count: {count}
18 <button onClick={() => setCount(count + 1)}>
19 Increment
20 </button>
21 </div>
22 );
23}Types of Props:
1. Primitive Props:
1function Greeting({ name, age, isVip, score }) {
2 return (
3 <div>
4 <h1>Hello {name}!</h1> {/* string */}
5 <p>Age: {age}</p> {/* number */}
6 <p>VIP: {isVip ? 'Yes' : 'No'}</p> {/* boolean */}
7 <p>Score: {score}</p> {/* number */}
8 </div>
9 );
10}
11
12// Usage
13<Greeting name="Bob" age={30} isVip={true} score={95.5} />2. Object Props:
1function ProductCard({ product }) {
2 return (
3 <div className="product-card">
4 <h3>{product.name}</h3>
5 <p>Price: ${product.price}</p>
6 <p>Category: {product.category}</p>
7 <p>Rating: {product.rating}/5</p>
8 </div>
9 );
10}
11
12// Usage
13const product = {
14 name: 'Laptop',
15 price: 999,
16 category: 'Electronics',
17 rating: 4.5
18};
19
20<ProductCard product={product} />3. Array Props:
1function TagList({ tags }) {
2 return (
3 <div className="tag-list">
4 {tags.map((tag, index) => (
5 <span key={index} className="tag">
6 {tag}
7 </span>
8 ))}
9 </div>
10 );
11}
12
13// Usage
14<TagList tags={['React', 'JavaScript', 'Frontend']} />4. Function Props (Event Handlers):
1function Button({ onClick, children, variant = 'primary' }) {
2 return (
3 <button
4 className={`btn btn-${variant}`}
5 onClick={onClick}
6 >
7 {children}
8 </button>
9 );
10}
11
12function App() {
13 const handleSave = () => {
14 console.log('Save clicked!');
15 };
16
17 const handleCancel = () => {
18 console.log('Cancel clicked!');
19 };
20
21 return (
22 <div>
23 <Button onClick={handleSave}>Save</Button>
24 <Button onClick={handleCancel} variant="secondary">
25 Cancel
26 </Button>
27 </div>
28 );
29}5. JSX Props (Render Props):
1function Card({ title, actions, children }) {
2 return (
3 <div className="card">
4 <div className="card-header">
5 <h3>{title}</h3>
6 {actions && <div className="card-actions">{actions}</div>}
7 </div>
8 <div className="card-body">
9 {children}
10 </div>
11 </div>
12 );
13}
14
15// Usage
16<Card
17 title="Settings"
18 actions={
19 <>
20 <button>Save</button>
21 <button>Reset</button>
22 </>
23 }
24>
25 <p>Configure your application settings here.</p>
26 <input type="text" placeholder="App name" />
27</Card>Advanced Props Patterns:
Props Spreading:
1function Input({ label, error, ...inputProps }) {
2 return (
3 <div className="form-field">
4 <label>{label}</label>
5 <input
6 className={error ? 'input-error' : 'input'}
7 {...inputProps} // Spreads remaining props to input
8 />
9 {error && <span className="error">{error}</span>}
10 </div>
11 );
12}
13
14// Usage - all extra props go to the input element
15<Input
16 label="Email"
17 type="email"
18 placeholder="Enter your email"
19 required
20 maxLength={100}
21 error="Email is required"
22/>Conditional Props:
1function Modal({ isOpen, title, children, onClose, size = 'medium' }) {
2 if (!isOpen) return null;
3
4 return (
5 <div className="modal-overlay" onClick={onClose}>
6 <div
7 className={`modal modal-${size}`}
8 onClick={e => e.stopPropagation()}
9 >
10 <div className="modal-header">
11 <h2>{title}</h2>
12 <button onClick={onClose}>×</button>
13 </div>
14 <div className="modal-body">
15 {children}
16 </div>
17 </div>
18 </div>
19 );
20}Component Composition Patterns:
1. Container and Presentational Components:
1// Presentational component - only concerned with display
2function TodoItem({ todo, onToggle, onDelete }) {
3 return (
4 <li className={todo.completed ? 'completed' : ''}>
5 <input
6 type="checkbox"
7 checked={todo.completed}
8 onChange={() => onToggle(todo.id)}
9 />
10 <span>{todo.text}</span>
11 <button onClick={() => onDelete(todo.id)}>Delete</button>
12 </li>
13 );
14}
15
16// Container component - manages state and logic
17function TodoList() {
18 const [todos, setTodos] = useState([]);
19
20 const handleToggle = (id) => {
21 setTodos(todos.map(todo =>
22 todo.id === id ? { ...todo, completed: !todo.completed } : todo
23 ));
24 };
25
26 const handleDelete = (id) => {
27 setTodos(todos.filter(todo => todo.id !== id));
28 };
29
30 return (
31 <ul>
32 {todos.map(todo => (
33 <TodoItem
34 key={todo.id}
35 todo={todo}
36 onToggle={handleToggle}
37 onDelete={handleDelete}
38 />
39 ))}
40 </ul>
41 );
42}2. Compound Components:
1function Tabs({ children, activeTab, onTabChange }) {
2 return (
3 <div className="tabs">
4 {React.Children.map(children, (child, index) =>
5 React.cloneElement(child, {
6 isActive: index === activeTab,
7 onClick: () => onTabChange(index)
8 })
9 )}
10 </div>
11 );
12}
13
14function Tab({ children, isActive, onClick }) {
15 return (
16 <button
17 className={`tab ${isActive ? 'active' : ''}`}
18 onClick={onClick}
19 >
20 {children}
21 </button>
22 );
23}
24
25// Usage
26function App() {
27 const [activeTab, setActiveTab] = useState(0);
28
29 return (
30 <Tabs activeTab={activeTab} onTabChange={setActiveTab}>
31 <Tab>Home</Tab>
32 <Tab>About</Tab>
33 <Tab>Contact</Tab>
34 </Tabs>
35 );
36}3. Higher-Order Component Pattern:
1function withAuth(WrappedComponent) {
2 return function AuthenticatedComponent(props) {
3 const [isAuthenticated, setIsAuthenticated] = useState(false);
4
5 useEffect(() => {
6 // Check authentication status
7 checkAuthStatus().then(setIsAuthenticated);
8 }, []);
9
10 if (!isAuthenticated) {
11 return <div>Please log in to access this page.</div>;
12 }
13
14 return <WrappedComponent {...props} />;
15 };
16}
17
18// Usage
19const ProtectedProfile = withAuth(UserProfile);
20const ProtectedSettings = withAuth(UserSettings);Props Validation and Documentation:
1import PropTypes from 'prop-types';
2
3function UserCard({
4 user,
5 showEmail = true,
6 onEdit,
7 className = '',
8 size = 'medium'
9}) {
10 return (
11 <div className={`user-card user-card-${size} ${className}`}>
12 <h3>{user.name}</h3>
13 {showEmail && <p>{user.email}</p>}
14 {onEdit && <button onClick={onEdit}>Edit</button>}
15 </div>
16 );
17}
18
19UserCard.propTypes = {
20 user: PropTypes.shape({
21 id: PropTypes.oneOfType([PropTypes.string, PropTypes.number]).isRequired,
22 name: PropTypes.string.isRequired,
23 email: PropTypes.string.isRequired
24 }).isRequired,
25 showEmail: PropTypes.bool,
26 onEdit: PropTypes.func,
27 className: PropTypes.string,
28 size: PropTypes.oneOf(['small', 'medium', 'large'])
29};Best Practices for Props:
Props and composition make React components incredibly flexible and reusable, enabling you to build complex UIs from simple, focused components.
Event handling in React is how you make your components interactive. React provides a synthetic event system that normalizes browser events, making your code more reliable and consistent across different browsers.
React Synthetic Events:
React wraps native DOM events in SyntheticEvent objects, which provide:
1function Button({ onClick, children }) {
2 const handleClick = (event) => {
3 event.preventDefault(); // Works consistently across browsers
4 console.log('Event type:', event.type); // Always 'click'
5 console.log('Target element:', event.target);
6
7 if (onClick) {
8 onClick(event);
9 }
10 };
11
12 return (
13 <button onClick={handleClick}>
14 {children}
15 </button>
16 );
17}Basic Event Handling Patterns:
1. Inline Event Handlers:
1function Counter() {
2 const [count, setCount] = useState(0);
3
4 return (
5 <div>
6 <p>Count: {count}</p>
7 {/* Simple inline handler */}
8 <button onClick={() => setCount(count + 1)}>
9 Increment
10 </button>
11
12 {/* Inline handler with logic */}
13 <button onClick={() => {
14 if (count > 0) {
15 setCount(count - 1);
16 }
17 }}>
18 Decrement
19 </button>
20 </div>
21 );
22}2. Separate Handler Functions:
1function TodoForm({ onAddTodo }) {
2 const [text, setText] = useState('');
3
4 const handleSubmit = (event) => {
5 event.preventDefault();
6
7 if (text.trim()) {
8 onAddTodo(text);
9 setText(''); // Clear form
10 }
11 };
12
13 const handleInputChange = (event) => {
14 setText(event.target.value);
15 };
16
17 const handleKeyPress = (event) => {
18 if (event.key === 'Enter' && !event.shiftKey) {
19 handleSubmit(event);
20 }
21 };
22
23 return (
24 <form onSubmit={handleSubmit}>
25 <input
26 type="text"
27 value={text}
28 onChange={handleInputChange}
29 onKeyPress={handleKeyPress}
30 placeholder="Enter todo item"
31 />
32 <button type="submit">Add Todo</button>
33 </form>
34 );
35}Common Event Types:
Mouse Events:
1function InteractiveCard({ title, content }) {
2 const [isHovered, setIsHovered] = useState(false);
3 const [clickCount, setClickCount] = useState(0);
4
5 return (
6 <div
7 className={`card ${isHovered ? 'hovered' : ''}`}
8 onClick={() => setClickCount(clickCount + 1)}
9 onMouseEnter={() => setIsHovered(true)}
10 onMouseLeave={() => setIsHovered(false)}
11 onDoubleClick={() => {
12 console.log('Double clicked!');
13 setClickCount(0);
14 }}
15 >
16 <h3>{title}</h3>
17 <p>{content}</p>
18 <small>Clicked {clickCount} times</small>
19 </div>
20 );
21}Keyboard Events:
1function SearchInput({ onSearch }) {
2 const [query, setQuery] = useState('');
3
4 const handleKeyDown = (event) => {
5 switch (event.key) {
6 case 'Enter':
7 onSearch(query);
8 break;
9 case 'Escape':
10 setQuery('');
11 event.target.blur();
12 break;
13 default:
14 break;
15 }
16 };
17
18 return (
19 <input
20 type="text"
21 value={query}
22 onChange={(e) => setQuery(e.target.value)}
23 onKeyDown={handleKeyDown}
24 placeholder="Press Enter to search, Escape to clear"
25 />
26 );
27}Form Events:
1function ContactForm() {
2 const [formData, setFormData] = useState({
3 name: '',
4 email: '',
5 message: ''
6 });
7 const [errors, setErrors] = useState({});
8
9 const handleInputChange = (event) => {
10 const { name, value } = event.target;
11 setFormData(prev => ({
12 ...prev,
13 [name]: value
14 }));
15
16 // Clear error when user starts typing
17 if (errors[name]) {
18 setErrors(prev => ({
19 ...prev,
20 [name]: ''
21 }));
22 }
23 };
24
25 const handleBlur = (event) => {
26 const { name, value } = event.target;
27
28 // Validate on blur
29 if (!value.trim()) {
30 setErrors(prev => ({
31 ...prev,
32 [name]: 'This field is required'
33 }));
34 }
35 };
36
37 const handleSubmit = (event) => {
38 event.preventDefault();
39
40 // Validation logic
41 const newErrors = {};
42 if (!formData.name.trim()) newErrors.name = 'Name is required';
43 if (!formData.email.trim()) newErrors.email = 'Email is required';
44 if (!formData.message.trim()) newErrors.message = 'Message is required';
45
46 if (Object.keys(newErrors).length > 0) {
47 setErrors(newErrors);
48 return;
49 }
50
51 // Submit form
52 console.log('Submitting:', formData);
53 };
54
55 return (
56 <form onSubmit={handleSubmit}>
57 <div>
58 <input
59 type="text"
60 name="name"
61 value={formData.name}
62 onChange={handleInputChange}
63 onBlur={handleBlur}
64 placeholder="Your Name"
65 />
66 {errors.name && <span className="error">{errors.name}</span>}
67 </div>
68
69 <div>
70 <input
71 type="email"
72 name="email"
73 value={formData.email}
74 onChange={handleInputChange}
75 onBlur={handleBlur}
76 placeholder="Your Email"
77 />
78 {errors.email && <span className="error">{errors.email}</span>}
79 </div>
80
81 <div>
82 <textarea
83 name="message"
84 value={formData.message}
85 onChange={handleInputChange}
86 onBlur={handleBlur}
87 placeholder="Your Message"
88 />
89 {errors.message && <span className="error">{errors.message}</span>}
90 </div>
91
92 <button type="submit">Send Message</button>
93 </form>
94 );
95}Event Handler Patterns:
1. Parameterized Event Handlers:
1function ButtonGroup({ buttons, onButtonClick }) {
2 return (
3 <div className="button-group">
4 {buttons.map(button => (
5 <button
6 key={button.id}
7 onClick={() => onButtonClick(button.id, button.action)}
8 >
9 {button.label}
10 </button>
11 ))}
12 </div>
13 );
14}
15
16// Usage
17const buttons = [
18 { id: 1, label: 'Save', action: 'save' },
19 { id: 2, label: 'Cancel', action: 'cancel' },
20 { id: 3, label: 'Delete', action: 'delete' }
21];
22
23function App() {
24 const handleButtonClick = (id, action) => {
25 console.log(`Button ${id} clicked with action: ${action}`);
26 };
27
28 return <ButtonGroup buttons={buttons} onButtonClick={handleButtonClick} />;
29}2. Custom Event Handlers:
1function useToggle(initialValue = false) {
2 const [value, setValue] = useState(initialValue);
3
4 const toggle = useCallback(() => {
5 setValue(prev => !prev);
6 }, []);
7
8 const setTrue = useCallback(() => {
9 setValue(true);
10 }, []);
11
12 const setFalse = useCallback(() => {
13 setValue(false);
14 }, []);
15
16 return [value, { toggle, setTrue, setFalse }];
17}
18
19function CollapsibleSection({ title, children }) {
20 const [isOpen, { toggle }] = useToggle(false);
21
22 return (
23 <div className="collapsible-section">
24 <div
25 className="section-header"
26 onClick={toggle}
27 role="button"
28 tabIndex={0}
29 onKeyPress={(event) => {
30 if (event.key === 'Enter' || event.key === ' ') {
31 toggle();
32 }
33 }}
34 >
35 <h3>{title}</h3>
36 <span>{isOpen ? '▼' : '▶'}</span>
37 </div>
38 {isOpen && (
39 <div className="section-content">
40 {children}
41 </div>
42 )}
43 </div>
44 );
45}3. Debounced Event Handlers:
1function useDebounce(value, delay) {
2 const [debouncedValue, setDebouncedValue] = useState(value);
3
4 useEffect(() => {
5 const handler = setTimeout(() => {
6 setDebouncedValue(value);
7 }, delay);
8
9 return () => {
10 clearTimeout(handler);
11 };
12 }, [value, delay]);
13
14 return debouncedValue;
15}
16
17function SearchBox({ onSearch }) {
18 const [searchTerm, setSearchTerm] = useState('');
19 const debouncedSearchTerm = useDebounce(searchTerm, 300);
20
21 useEffect(() => {
22 if (debouncedSearchTerm) {
23 onSearch(debouncedSearchTerm);
24 }
25 }, [debouncedSearchTerm, onSearch]);
26
27 return (
28 <input
29 type="text"
30 value={searchTerm}
31 onChange={(event) => setSearchTerm(event.target.value)}
32 placeholder="Search..."
33 />
34 );
35}Event Handling Best Practices:
1. Prevent Memory Leaks:
1function WindowSize() {
2 const [windowSize, setWindowSize] = useState({
3 width: window.innerWidth,
4 height: window.innerHeight
5 });
6
7 useEffect(() => {
8 const handleResize = () => {
9 setWindowSize({
10 width: window.innerWidth,
11 height: window.innerHeight
12 });
13 };
14
15 // Add event listener
16 window.addEventListener('resize', handleResize);
17
18 // Cleanup function - remove event listener
19 return () => {
20 window.removeEventListener('resize', handleResize);
21 };
22 }, []);
23
24 return (
25 <div>
26 Window size: {windowSize.width} x {windowSize.height}
27 </div>
28 );
29}2. Performance Optimization:
1// ❌ Creates new function on every render
2function SlowButton({ onClick, children }) {
3 return (
4 <button onClick={() => onClick()}>
5 {children}
6 </button>
7 );
8}
9
10// ✅ Stable function reference
11function OptimizedButton({ onClick, children }) {
12 const handleClick = useCallback(() => {
13 onClick();
14 }, [onClick]);
15
16 return (
17 <button onClick={handleClick}>
18 {children}
19 </button>
20 );
21}3. Accessibility Considerations:
1function AccessibleButton({ onClick, disabled, children, ariaLabel }) {
2 const handleKeyPress = (event) => {
3 if (event.key === 'Enter' || event.key === ' ') {
4 event.preventDefault();
5 onClick();
6 }
7 };
8
9 return (
10 <button
11 onClick={onClick}
12 onKeyPress={handleKeyPress}
13 disabled={disabled}
14 aria-label={ariaLabel}
15 tabIndex={disabled ? -1 : 0}
16 >
17 {children}
18 </button>
19 );
20}React's event system makes it easy to create interactive, responsive user interfaces while maintaining clean, predictable code patterns.
Master React fundamentals with hands-on examples of JSX syntax, functional components, props, and event handling. Build real interactive components while learning core React concepts.
1<!DOCTYPE html>
2<html lang="en">
3<head>
4 <meta charset="UTF-8">
5 <meta name="viewport" content="width=device-width, initial-scale=1.0">
6 <title>React Basics & Components Demo</title>
7 <style>
8 * {
9 margin: 0;
10 padding: 0;
11 box-sizing: border-box;
12 }
13
14 body {
15 font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, sans-serif;
16 background: linear-gradient(135deg, #667eea 0%, #764ba2 100%);
17 min-height: 100vh;
18 padding: 20px;
19 }
20
21 .container {
22 max-width: 1200px;
23 margin: 0 auto;
24 }
25
26 .header {
27 text-align: center;
28 color: white;
29 margin-bottom: 40px;
30 }
31
32 .header h1 {
33 font-size: 3rem;
34 margin-bottom: 10px;
35 text-shadow: 2px 2px 4px rgba(0,0,0,0.3);
36 }
37
38 .header p {
39 font-size: 1.2rem;
40 opacity: 0.9;
41 }
42
43 .demo-section {
44 background: white;
45 border-radius: 15px;
46 padding: 30px;
47 margin-bottom: 30px;
48 box-shadow: 0 10px 30px rgba(0,0,0,0.2);
49 }
50
51 .demo-section h2 {
52 color: #2d3748;
53 margin-bottom: 25px;
54 font-size: 1.8rem;
55 }
56
57 .demo-section h3 {
58 color: #4a5568;
59 margin-bottom: 15px;
60 font-size: 1.3rem;
61 }
62
63 .demo-grid {
64 display: grid;
65 grid-template-columns: repeat(auto-fit, minmax(300px, 1fr));
66 gap: 20px;
67 margin: 20px 0;
68 }
69
70 .component-example {
71 background: #f7fafc;
72 border: 2px solid #e2e8f0;
73 border-radius: 10px;
74 padding: 20px;
75 transition: transform 0.3s ease, box-shadow 0.3s ease;
76 }
77
78 .component-example:hover {
79 transform: translateY(-2px);
80 box-shadow: 0 8px 25px rgba(0,0,0,0.15);
81 }
82
83 .component-title {
84 font-size: 1.1rem;
85 font-weight: bold;
86 color: #2d3748;
87 margin-bottom: 15px;
88 padding-bottom: 10px;
89 border-bottom: 2px solid #667eea;
90 }
91
92 /* Button Styles */
93 .btn {
94 background: #667eea;
95 color: white;
96 border: none;
97 padding: 10px 20px;
98 border-radius: 8px;
99 cursor: pointer;
100 font-size: 1rem;
101 margin: 5px;
102 transition: all 0.3s ease;
103 display: inline-flex;
104 align-items: center;
105 gap: 8px;
106 }
107
108 .btn:hover {
109 background: #5a67d8;
110 transform: scale(1.05);
111 }
112
113 .btn:active {
114 transform: scale(0.95);
115 }
116
117 .btn-primary { background: #667eea; }
118 .btn-secondary { background: #718096; }
119 .btn-success { background: #48bb78; }
120 .btn-danger { background: #f56565; }
121 .btn-warning { background: #ed8936; }
122
123 .btn:disabled {
124 background: #a0aec0;
125 cursor: not-allowed;
126 transform: none;
127 }
128
129 /* Counter Styles */
130 .counter {
131 text-align: center;
132 padding: 20px;
133 background: white;
134 border-radius: 10px;
135 border: 2px solid #e2e8f0;
136 }
137
138 .counter-display {
139 font-size: 3rem;
140 font-weight: bold;
141 color: #667eea;
142 margin: 20px 0;
143 text-shadow: 1px 1px 2px rgba(0,0,0,0.1);
144 }
145
146 .counter-buttons {
147 display: flex;
148 gap: 10px;
149 justify-content: center;
150 flex-wrap: wrap;
151 }
152
153 /* Form Styles */
154 .form-group {
155 margin-bottom: 20px;
156 }
157
158 .form-label {
159 display: block;
160 margin-bottom: 5px;
161 font-weight: bold;
162 color: #2d3748;
163 }
164
165 .form-input {
166 width: 100%;
167 padding: 12px;
168 border: 2px solid #e2e8f0;
169 border-radius: 8px;
170 font-size: 1rem;
171 transition: border-color 0.3s ease;
172 }
173
174 .form-input:focus {
175 outline: none;
176 border-color: #667eea;
177 box-shadow: 0 0 0 3px rgba(102, 126, 234, 0.1);
178 }
179
180 .form-input.error {
181 border-color: #f56565;
182 }
183
184 .error-message {
185 color: #f56565;
186 font-size: 0.875rem;
187 margin-top: 5px;
188 }
189
190 .success-message {
191 color: #48bb78;
192 font-size: 0.875rem;
193 margin-top: 5px;
194 }
195
196 /* User Profile Styles */
197 .user-profile {
198 display: flex;
199 align-items: center;
200 gap: 15px;
201 padding: 20px;
202 background: white;
203 border-radius: 10px;
204 border: 1px solid #e2e8f0;
205 margin: 10px 0;
206 }
207
208 .avatar {
209 width: 60px;
210 height: 60px;
211 border-radius: 50%;
212 background: linear-gradient(135deg, #667eea, #764ba2);
213 display: flex;
214 align-items: center;
215 justify-content: center;
216 color: white;
217 font-size: 1.5rem;
218 font-weight: bold;
219 }
220
221 .user-info h4 {
222 margin: 0 0 5px 0;
223 color: #2d3748;
224 }
225
226 .user-info p {
227 margin: 0;
228 color: #718096;
229 font-size: 0.9rem;
230 }
231
232 .status-online {
233 color: #48bb78;
234 font-weight: bold;
235 }
236
237 .status-offline {
238 color: #a0aec0;
239 font-weight: bold;
240 }
241
242 /* Interactive Elements */
243 .interactive-demo {
244 background: #e6fffa;
245 border: 2px solid #81e6d9;
246 border-radius: 10px;
247 padding: 20px;
248 margin: 20px 0;
249 }
250
251 .event-log {
252 background: #1a202c;
253 color: #e2e8f0;
254 padding: 15px;
255 border-radius: 8px;
256 font-family: monospace;
257 font-size: 0.9rem;
258 max-height: 200px;
259 overflow-y: auto;
260 margin: 15px 0;
261 }
262
263 .highlight {
264 background: #fef3c7;
265 color: #92400e;
266 padding: 2px 6px;
267 border-radius: 4px;
268 font-weight: bold;
269 }
270
271 .code-snippet {
272 background: #f7fafc;
273 border: 1px solid #e2e8f0;
274 border-radius: 8px;
275 padding: 15px;
276 font-family: monospace;
277 font-size: 0.9rem;
278 color: #2d3748;
279 margin: 15px 0;
280 overflow-x: auto;
281 }
282
283 @media (max-width: 768px) {
284 .header h1 {
285 font-size: 2rem;
286 }
287
288 .demo-grid {
289 grid-template-columns: 1fr;
290 }
291
292 .counter-buttons {
293 flex-direction: column;
294 }
295
296 .user-profile {
297 flex-direction: column;
298 text-align: center;
299 }
300 }
301 </style>
302</head>
303<body>
304 <div class="container">
305 <div class="header">
306 <h1>⚛️ React Basics & Components</h1>
307 <p>Learn JSX, functional components, props, and event handling</p>
308 </div>
309
310 <!-- JSX Syntax Demo -->
311 <div class="demo-section">
312 <h2>📝 JSX Syntax in Action</h2>
313 <p>JSX lets you write HTML-like code in JavaScript. Here's a live example:</p>
314
315 <div class="code-snippet">
316// JSX Expression
317const greeting = <h1>Hello, {userName}!</h1>;
318
319// Conditional Rendering
320{isLoggedIn ? <WelcomeMessage /> : <LoginPrompt />}
321
322// List Rendering
323{users.map(user => <UserCard key={user.id} user={user} />)}
324 </div>
325
326 <div class="interactive-demo">
327 <h3>🎯 Try JSX Features:</h3>
328 <div class="demo-grid">
329 <div class="component-example">
330 <div class="component-title">Dynamic Content</div>
331 <div id="jsx-demo-1">
332 <p>Current time: <span id="current-time"></span></p>
333 <p>Random number: <span id="random-number"></span></p>
334 </div>
335 <button class="btn btn-primary" onclick="updateDynamicContent()">
336 🔄 Update Content
337 </button>
338 </div>
339
340 <div class="component-example">
341 <div class="component-title">Conditional Rendering</div>
342 <div id="conditional-demo">
343 <p>Status: <span id="login-status">Logged out</span></p>
344 </div>
345 <button class="btn btn-success" onclick="toggleLoginStatus()">
346 🔐 Toggle Login
347 </button>
348 </div>
349 </div>
350 </div>
351 </div>
352
353 <!-- Functional Components Demo -->
354 <div class="demo-section">
355 <h2>🔧 Functional Components</h2>
356 <p>Components are JavaScript functions that return JSX. They're reusable and composable.</p>
357
358 <div class="demo-grid">
359 <div class="component-example">
360 <div class="component-title">User Profile Component</div>
361 <div id="user-profiles"></div>
362 <button class="btn btn-primary" onclick="generateRandomUser()">
363 👤 Generate User
364 </button>
365 </div>
366
367 <div class="component-example">
368 <div class="component-title">Button Variants</div>
369 <div style="display: flex; flex-wrap: wrap; gap: 10px;">
370 <button class="btn btn-primary">Primary</button>
371 <button class="btn btn-secondary">Secondary</button>
372 <button class="btn btn-success">Success</button>
373 <button class="btn btn-danger">Danger</button>
374 <button class="btn btn-warning">Warning</button>
375 <button class="btn" disabled>Disabled</button>
376 </div>
377 <p style="margin-top: 15px; font-size: 0.9rem; color: #718096;">
378 Same component, different <span class="highlight">props</span>
379 </p>
380 </div>
381 </div>
382 </div>
383
384 <!-- Props Demo -->
385 <div class="demo-section">
386 <h2>📦 Props: Passing Data to Components</h2>
387 <p>Props make components reusable by allowing different data inputs.</p>
388
389 <div class="interactive-demo">
390 <h3>🎯 Props in Action:</h3>
391 <div class="form-group">
392 <label class="form-label" for="prop-name">Name:</label>
393 <input
394 type="text"
395 id="prop-name"
396 class="form-input"
397 placeholder="Enter a name"
398 onkeyup="updatePropsDemo()"
399 />
400 </div>
401
402 <div class="form-group">
403 <label class="form-label" for="prop-email">Email:</label>
404 <input
405 type="email"
406 id="prop-email"
407 class="form-input"
408 placeholder="Enter an email"
409 onkeyup="updatePropsDemo()"
410 />
411 </div>
412
413 <div class="form-group">
414 <label class="form-label">Status:</label>
415 <label><input type="radio" name="status" value="online" onchange="updatePropsDemo()" checked> Online</label>
416 <label><input type="radio" name="status" value="offline" onchange="updatePropsDemo()"> Offline</label>
417 </div>
418
419 <div id="props-result">
420 <!-- Dynamic content will be inserted here -->
421 </div>
422 </div>
423 </div>
424
425 <!-- Event Handling Demo -->
426 <div class="demo-section">
427 <h2>🎯 Event Handling</h2>
428 <p>React uses synthetic events for consistent cross-browser behavior.</p>
429
430 <div class="demo-grid">
431 <div class="component-example">
432 <div class="component-title">Interactive Counter</div>
433 <div class="counter">
434 <div class="counter-display" id="counter-display">0</div>
435 <div class="counter-buttons">
436 <button class="btn btn-danger" onclick="updateCounter(-5)">-5</button>
437 <button class="btn btn-secondary" onclick="updateCounter(-1)">-1</button>
438 <button class="btn btn-warning" onclick="resetCounter()">Reset</button>
439 <button class="btn btn-secondary" onclick="updateCounter(1)">+1</button>
440 <button class="btn btn-success" onclick="updateCounter(5)">+5</button>
441 </div>
442 </div>
443 </div>
444
445 <div class="component-example">
446 <div class="component-title">Event Logger</div>
447 <div>
448 <button class="btn btn-primary" onclick="logEvent('click', 'Button clicked')">
449 🖱️ Click Me
450 </button>
451 <button class="btn btn-secondary" onmouseover="logEvent('mouseover', 'Mouse entered')" onmouseout="logEvent('mouseout', 'Mouse left')">
452 👆 Hover Me
453 </button>
454 <input
455 type="text"
456 class="form-input"
457 placeholder="Type here..."
458 oninput="logEvent('input', 'Text changed: ' + this.value)"
459 style="margin-top: 10px;"
460 />
461 </div>
462 <div class="event-log" id="event-log">
463 Event log will appear here...
464 </div>
465 <button class="btn btn-warning" onclick="clearEventLog()">Clear Log</button>
466 </div>
467 </div>
468 </div>
469
470 <!-- Form Handling Demo -->
471 <div class="demo-section">
472 <h2>📋 Form Handling</h2>
473 <p>React forms use controlled components where React manages the form state.</p>
474
475 <div class="component-example">
476 <div class="component-title">Contact Form</div>
477 <form id="contact-form" onsubmit="handleFormSubmit(event)">
478 <div class="form-group">
479 <label class="form-label" for="contact-name">Name:</label>
480 <input
481 type="text"
482 id="contact-name"
483 name="name"
484 class="form-input"
485 required
486 />
487 <div id="name-error" class="error-message" style="display: none;"></div>
488 </div>
489
490 <div class="form-group">
491 <label class="form-label" for="contact-email">Email:</label>
492 <input
493 type="email"
494 id="contact-email"
495 name="email"
496 class="form-input"
497 required
498 />
499 <div id="email-error" class="error-message" style="display: none;"></div>
500 </div>
501
502 <div class="form-group">
503 <label class="form-label" for="contact-message">Message:</label>
504 <textarea
505 id="contact-message"
506 name="message"
507 class="form-input"
508 rows="4"
509 required
510 ></textarea>
511 <div id="message-error" class="error-message" style="display: none;"></div>
512 </div>
513
514 <button type="submit" class="btn btn-primary">
515 📤 Send Message
516 </button>
517 </form>
518
519 <div id="form-success" class="success-message" style="display: none; margin-top: 15px;">
520 ✅ Message sent successfully!
521 </div>
522 </div>
523 </div>
524
525 <div style="text-align: center; margin-top: 40px; padding: 30px; background: rgba(255,255,255,0.1); border-radius: 15px;">
526 <h3 style="color: white; margin-bottom: 15px;">🎉 You've Mastered React Basics!</h3>
527 <p style="color: white; opacity: 0.9; font-size: 1.1rem;">
528 ✅ JSX Syntax | ✅ Functional Components | ✅ Props | ✅ Event Handling
529 </p>
530 </div>
531 </div>
532
533 <script>
534 // Global state for demos
535 let counter = 0;
536 let eventLogCount = 0;
537 let isLoggedIn = false;
538 let users = [];
539
540 // JSX Demo Functions
541 function updateDynamicContent() {
542 document.getElementById('current-time').textContent = new Date().toLocaleTimeString();
543 document.getElementById('random-number').textContent = Math.floor(Math.random() * 100);
544 }
545
546 function toggleLoginStatus() {
547 isLoggedIn = !isLoggedIn;
548 const statusElement = document.getElementById('login-status');
549 statusElement.textContent = isLoggedIn ? 'Logged in' : 'Logged out';
550 statusElement.className = isLoggedIn ? 'status-online' : 'status-offline';
551 }
552
553 // Component Demo Functions
554 function createUserProfile(user) {
555 return `
556 <div class="user-profile">
557 <div class="avatar">${user.name.charAt(0).toUpperCase()}</div>
558 <div class="user-info">
559 <h4>${user.name}</h4>
560 <p>${user.email}</p>
561 <p class="${user.isOnline ? 'status-online' : 'status-offline'}">
562 ${user.isOnline ? '🟢 Online' : '⚫ Offline'}
563 </p>
564 </div>
565 </div>
566 `;
567 }
568
569 function generateRandomUser() {
570 const names = ['Alice Johnson', 'Bob Smith', 'Carol Davis', 'David Wilson', 'Emma Brown'];
571 const domains = ['example.com', 'demo.org', 'test.net'];
572
573 const name = names[Math.floor(Math.random() * names.length)];
574 const email = name.toLowerCase().replace(' ', '.') + '@' + domains[Math.floor(Math.random() * domains.length)];
575 const isOnline = Math.random() > 0.5;
576
577 const user = { name, email, isOnline };
578 users.push(user);
579
580 const userProfilesElement = document.getElementById('user-profiles');
581 userProfilesElement.innerHTML = users.map(createUserProfile).join('');
582 }
583
584 // Props Demo Functions
585 function updatePropsDemo() {
586 const name = document.getElementById('prop-name').value || 'Guest User';
587 const email = document.getElementById('prop-email').value || '[email protected]';
588 const status = document.querySelector('input[name="status"]:checked').value;
589
590 const isOnline = status === 'online';
591 const user = { name, email, isOnline };
592
593 document.getElementById('props-result').innerHTML = `603`;
604 }
605
606 // Counter Demo Functions
607 function updateCounter(change) {
608 counter += change;
609 const displayElement = document.getElementById('counter-display');
610 displayElement.textContent = counter;
611
612 // Add animation
613 displayElement.style.transform = 'scale(1.1)';
614 setTimeout(() => {
615 displayElement.style.transform = 'scale(1)';
616 }, 150);
617 }
618
619 function resetCounter() {
620 counter = 0;
621 document.getElementById('counter-display').textContent = counter;
622 }
623
624 // Event Logging Functions
625 function logEvent(eventType, description) {
626 eventLogCount++;
627 const timestamp = new Date().toLocaleTimeString();
628 const logElement = document.getElementById('event-log');
629
630 const newLogEntry = `[${timestamp}] ${eventType}: ${description}`;
631
632 if (logElement.textContent === 'Event log will appear here...') {
633 logElement.textContent = newLogEntry;
634 } else {
635 logElement.textContent = logElement.textContent + '\n' + newLogEntry;
636 }
637
638 logElement.scrollTop = logElement.scrollHeight;
639 }
640
641 function clearEventLog() {
642 document.getElementById('event-log').textContent = 'Event log will appear here...';
643 eventLogCount = 0;
644 }
645
646 // Form Handling Functions
647 function handleFormSubmit(event) {
648 event.preventDefault();
649
650 // Clear previous errors
651 const errorElements = document.querySelectorAll('.error-message');
652 errorElements.forEach(el => el.style.display = 'none');
653
654 const inputs = document.querySelectorAll('.form-input');
655 inputs.forEach(input => input.classList.remove('error'));
656
657 // Get form data
658 const formData = new FormData(event.target);
659 const data = Object.fromEntries(formData);
660
661 // Simple validation
662 let hasErrors = false;
663
664 if (!data.name.trim()) {
665 showError('name-error', 'Name is required');
666 hasErrors = true;
667 }
668
669 if (!data.email.trim()) {
670 showError('email-error', 'Email is required');
671 hasErrors = true;
672 } else if (!isValidEmail(data.email)) {
673 showError('email-error', 'Please enter a valid email');
674 hasErrors = true;
675 }
676
677 if (!data.message.trim()) {
678 showError('message-error', 'Message is required');
679 hasErrors = true;
680 }
681
682 if (!hasErrors) {
683 // Simulate form submission
684 document.getElementById('form-success').style.display = 'block';
685 event.target.reset();
686
687 setTimeout(() => {
688 document.getElementById('form-success').style.display = 'none';
689 }, 5000);
690
691 logEvent('submit', `Form submitted with name: ${data.name}`);
692 }
693 }
694
695 function showError(elementId, message) {
696 const errorElement = document.getElementById(elementId);
697 errorElement.textContent = message;
698 errorElement.style.display = 'block';
699
700 const inputName = elementId.replace('-error', '');
701 const input = document.getElementById('contact-' + inputName);
702 if (input) {
703 input.classList.add('error');
704 }
705 }
706
707 function isValidEmail(email) {
708 const emailRegex = /^[^\s@]+@[^\s@]+\.[^\s@]+$/;
709 return emailRegex.test(email);
710 }
711
712 // Initialize demos on page load
713 document.addEventListener('DOMContentLoaded', function() {
714 // Initialize dynamic content
715 updateDynamicContent();
716
717 // Initialize props demo
718 updatePropsDemo();
719
720 // Generate initial user
721 generateRandomUser();
722
723 // Update time every second
724 setInterval(updateDynamicContent, 1000);
725
726 console.log('React Basics & Components Demo loaded! ⚛️');
727 console.log('Try interacting with the components to see React patterns in action');
728 });
729 </script>
730</body>
731</html>This comprehensive React demonstration showcases all the fundamental concepts covered in Lesson 2:
🎯 Complete React Basics Coverage:
1. JSX Syntax Mastery:
2. Functional Components in Action:
3. Props System Demonstration:
4. Event Handling Patterns:
5. Form Handling & Validation:
6. Component Lifecycle Simulation:
7. Modern React Patterns:
8. Interactive Learning Elements:
9. Best Practices Demonstration:
10. Production-Ready Patterns:
This demonstration provides hands-on experience with all fundamental React concepts, making abstract ideas concrete through interactive examples. Students can see immediate results and understand how React components work in real applications, preparing them for building their own React applications.
Excellent work mastering React basics! You now understand JSX syntax, functional components, props, and event handling - the core building blocks of React development. In our next lesson, we'll explore React State & Props in greater depth, learning about the useState hook, controlled components, state management patterns, and advanced prop techniques. Get ready to build truly interactive and dynamic React applications!
Your progress is saved in this browser, on this device only.