React Introduction and Core Concepts: Building Modern User Interfaces with JavaScript โ
What is React? โ
React is a JavaScript library developed by Facebook (now Meta) for building user interfaces, especially single-page applications (SPAs). It introduced revolutionary concepts like component-based architecture, virtual DOM, and declarative programming, fundamentally changing the way we build frontends.
Imagine building a LEGO city:
- Traditional Web Development: Like sculpting from a single block of clayโmodifying one part may affect the whole
- React Development: Like building with LEGO blocksโeach component is an independent brick that can be freely combined and replaced
// Basic React component structure
function WelcomeCard({ name, age }) {
return (
<div className="welcome-card">
<h2>Welcome, {name}!</h2>
<p>You are {age} years old.</p>
<button onClick={() => alert(`Hello, ${name}!`)}>Click to Greet</button>
</div>
);
}
// Using the component
function App() {
return (
<div className="app">
<WelcomeCard name="John Smith" age={25} />
<WelcomeCard name="Jane Doe" age={30} />
</div>
);
}React's Origin Story โ
Facebook's Pain Points (Early 2010s) โ
Before React emerged, Facebook faced serious frontend development challenges:
Problem 1: Complex UI State Management
// Traditional DOM manipulation problems
var likeButton = document.getElementById("like-button");
var likeCount = 0;
likeButton.onclick = function () {
likeCount++;
likeButton.textContent = "Like (" + likeCount + ")";
// Need to manually update all related DOM elements
document.getElementById("like-count").textContent = likeCount;
document.getElementById("like-status").textContent =
likeCount > 0 ? "Someone liked!" : "No likes yet";
};
// Have to manually update multiple places every time state changesProblem 2: Code Duplication and Maintenance Difficulties
// Repeated code for similar functionality
function createProfileCard(user) {
var card = document.createElement("div");
card.className = "profile-card";
var avatar = document.createElement("img");
avatar.src = user.avatar;
card.appendChild(avatar);
var name = document.createElement("h3");
name.textContent = user.name;
card.appendChild(name);
var bio = document.createElement("p");
bio.textContent = user.bio;
card.appendChild(bio);
// 50 lines of similar DOM manipulation code...
}
function createFriendCard(friend) {
// Another 50 lines of nearly identical code...
}Problem 3: Unclear Data Flow When applications became complex, it was hard to track how data flowed through the app. A small change could cause unexpected side effects.
Jordan Walke's Innovation (2011-2013) โ
In 2011, Facebook engineer Jordan Walke started addressing these problems. He introduced several revolutionary concepts:
1. Functional UI Programming โ
// Jordan's early idea: UI = f(state)
function renderUI(state) {
return {
type: "div",
props: { className: "app" },
children: [
{
type: "h1",
props: { children: `Count: ${state.count}` },
},
{
type: "button",
props: {
children: "Increment",
onClick: () => updateState({ count: state.count + 1 }),
},
},
],
};
}2. Virtual DOM Concept โ
// Core idea of Virtual DOM
// 1. Build virtual DOM tree in memory
var oldVirtualDOM = {
type: "div",
props: { className: "container" },
children: [
{ type: "h1", props: { children: "Old Title" } },
{ type: "p", props: { children: "Old Content" } },
],
};
// 2. Create new virtual DOM
var newVirtualDOM = {
type: "div",
props: { className: "container" },
children: [
{ type: "h1", props: { children: "New Title" } }, // Changed
{ type: "p", props: { children: "Old Content" } }, // Unchanged
],
};
// 3. Compare differences, only update what changed
var diff = {
type: "UPDATE",
path: [0, "props", "children"],
newValue: "New Title",
};3. JSX Syntax Sugar โ
// Early React: Using JavaScript objects to describe UI
React.createElement(
"div",
{ className: "greeting" },
React.createElement("h1", null, "Hello, ", this.props.name)
);
// JSX: More intuitive syntax sugar
<div className="greeting">
<h1>Hello, {this.props.name}</h1>
</div>;
// JSX compiles to the JavaScript code aboveReact's Public Release (2013-2015) โ
May 2013: React first publicly released at Facebook's F8 conference
July 2015: React Native released, bringing React philosophy to mobile
// React Native: Same component philosophy, different platform
import React from "react";
import { View, Text, TouchableOpacity } from "react-native";
function WelcomeButton({ name, onPress }) {
return (
<TouchableOpacity onPress={onPress}>
<View style={{ padding: 20, backgroundColor: "#007AFF" }}>
<Text style={{ color: "white", fontSize: 18 }}>Welcome, {name}!</Text>
</View>
</TouchableOpacity>
);
}React's Core Features โ
1. Component-Based โ
Components are the basic building blocks of React applications. Each component is an independent, reusable UI piece:
// Function component (modern recommended approach)
function UserCard({ user }) {
return (
<div className="user-card">
<img src={user.avatar} alt={user.name} />
<div className="user-info">
<h3>{user.name}</h3>
<p>{user.email}</p>
<p className="user-role">{user.role}</p>
</div>
<div className="user-actions">
<button onClick={() => followUser(user.id)}>Follow</button>
<button onClick={() => messageUser(user.id)}>Message</button>
</div>
</div>
);
}
// Using the component
function App() {
const users = [
{
id: 1,
name: "John Smith",
email: "[email protected]",
role: "Frontend Engineer",
avatar: "avatar1.jpg",
},
{
id: 2,
name: "Jane Doe",
email: "[email protected]",
role: "Backend Engineer",
avatar: "avatar2.jpg",
},
];
return (
<div className="user-list">
{users.map((user) => (
<UserCard key={user.id} user={user} />
))}
</div>
);
}2. Declarative Programming โ
React uses declarative programmingโyou just describe what the UI should look like, not how to implement it:
// Declarative: Describe what you want
function TodoList({ todos, onDeleteTodo, onToggleTodo }) {
return (
<ul className="todo-list">
{todos
.filter((todo) => !todo.completed) // Only show uncompleted
.sort((a, b) => a.priority - b.priority) // Sort by priority
.map((todo) => (
<TodoItem
key={todo.id}
todo={todo}
onDelete={onDeleteTodo}
onToggle={onToggleTodo}
/>
))}
</ul>
);
}
// Compare with imperative: Describe how to implement
function renderTodoList(todos) {
var ul = document.createElement("ul");
ul.className = "todo-list";
// Manually filter
var incompleteTodos = todos.filter(function (todo) {
return !todo.completed;
});
// Manually sort
incompleteTodos.sort(function (a, b) {
return a.priority - b.priority;
});
// Manually create and add elements
incompleteTodos.forEach(function (todo) {
var li = document.createElement("li");
li.textContent = todo.text;
var deleteBtn = document.createElement("button");
deleteBtn.textContent = "Delete";
deleteBtn.onclick = function () {
deleteTodo(todo.id);
};
li.appendChild(deleteBtn);
ul.appendChild(li);
});
return ul;
}3. Virtual DOM โ
Virtual DOM is React's core technology for performance optimization:
// Virtual DOM workflow
// 1. When state changes, React creates new virtual DOM
function Counter() {
const [count, setCount] = useState(0);
return (
<div>
<p>Count: {count}</p>
<button onClick={() => setCount(count + 1)}>
Increment
</button>
</div>
);
}
// 2. React compares new and old virtual DOM differences
// Old virtual DOM
{
type: 'div',
props: {},
children: [
{ type: 'p', props: { children: 'Count: 0' } },
{ type: 'button', props: { children: 'Increment', onClick: [Function] } }
]
}
// New virtual DOM
{
type: 'div',
props: {},
children: [
{ type: 'p', props: { children: 'Count: 1' } }, // Only this changed
{ type: 'button', props: { children: 'Increment', onClick: [Function] } }
]
}
// 3. Calculate minimal DOM update operations
// Only update <p> element's content, not re-render entire component4. Unidirectional Data Flow โ
React uses unidirectional data flow, making data flow more predictable:
// Parent component
function ShoppingCart() {
const [items, setItems] = useState([
{ id: 1, name: "React Tutorial", price: 99, quantity: 1 },
{ id: 2, name: "JavaScript Advanced", price: 129, quantity: 2 },
]);
const updateQuantity = (id, newQuantity) => {
setItems(
items.map((item) =>
item.id === id ? { ...item, quantity: newQuantity } : item
)
);
};
const removeItem = (id) => {
setItems(items.filter((item) => item.id !== id));
};
const total = items.reduce(
(sum, item) => sum + item.price * item.quantity,
0
);
return (
<div className="shopping-cart">
<h2>Shopping Cart</h2>
{items.map((item) => (
<CartItem
key={item.id}
item={item}
onUpdateQuantity={updateQuantity}
onRemove={removeItem}
/>
))}
<div className="cart-total">Total: ยฅ{total}</div>
</div>
);
}
// Child component can only receive props, cannot directly modify parent state
function CartItem({ item, onUpdateQuantity, onRemove }) {
return (
<div className="cart-item">
<h4>{item.name}</h4>
<p>ยฅ{item.price}</p>
<div className="quantity-controls">
<button
onClick={() => onUpdateQuantity(item.id, item.quantity - 1)}
disabled={item.quantity <= 1}
>
-
</button>
<span>{item.quantity}</span>
<button onClick={() => onUpdateQuantity(item.id, item.quantity + 1)}>
+
</button>
<button onClick={() => onRemove(item.id)}>Delete</button>
</div>
</div>
);
}How React Works โ
1. JSX Transformation Process โ
JSX syntax is transformed into JavaScript code by tools like Babel:
// JSX code
function App() {
const user = { name: "John Smith", age: 25 };
return (
<div className="app">
<h1>Welcome, {user.name}!</h1>
<p>You are {user.age} years old.</p>
{user.age >= 18 && <p>You are an adult</p>}
</div>
);
}
// Transformed JavaScript code
function App() {
const user = { name: "John Smith", age: 25 };
return React.createElement(
"div",
{ className: "app" },
React.createElement("h1", null, "Welcome, ", user.name, "!"),
React.createElement("p", null, "You are ", user.age, " years old."),
user.age >= 18 && React.createElement("p", null, "You are an adult")
);
}
// More complex example transformation
function UserList({ users }) {
return (
<ul className="user-list">
{users.map((user) => (
<li key={user.id} className="user-item">
<strong>{user.name}</strong>: {user.email}
</li>
))}
</ul>
);
}
// After transformation
function UserList({ users }) {
return React.createElement(
"ul",
{ className: "user-list" },
users.map((user) =>
React.createElement(
"li",
{ key: user.id, className: "user-item" },
React.createElement("strong", null, user.name),
": ",
user.email
)
)
);
}2. Component Lifecycle (Function Components) โ
Modern React uses Hooks to manage component lifecycle:
import { useState, useEffect, useRef, memo } from "react";
// Function component lifecycle with Hooks
function UserProfile({ userId }) {
// State management
const [user, setUser] = useState(null);
const [loading, setLoading] = useState(true);
const [error, setError] = useState(null);
// Side effect: Similar to componentDidMount and componentDidUpdate
useEffect(() => {
async function fetchUser() {
try {
setLoading(true);
const response = await fetch(`/api/users/${userId}`);
const userData = await response.json();
setUser(userData);
} catch (err) {
setError(err.message);
} finally {
setLoading(false);
}
}
fetchUser();
}, [userId]); // Dependency array: re-execute when userId changes
// Cleanup function: Similar to componentWillUnmount
useEffect(() => {
const timer = setInterval(() => {
console.log("User data periodic refresh");
}, 30000);
return () => clearInterval(timer); // Cleanup timer when component unmounts
}, []);
// Ref: Direct DOM element access
const avatarRef = useRef(null);
useEffect(() => {
if (avatarRef.current) {
// Can directly manipulate DOM element
avatarRef.current.classList.add("fade-in");
}
}, [user]);
// Conditional rendering
if (loading) return <div>Loading...</div>;
if (error) return <div>Error: {error}</div>;
if (!user) return <div>User not found</div>;
return (
<div className="user-profile">
<img ref={avatarRef} src={user.avatar} alt={`${user.name}'s avatar`} />
<h2>{user.name}</h2>
<p>{user.bio}</p>
<div className="user-stats">
<span>Following: {user.following}</span>
<span>Followers: {user.followers}</span>
</div>
</div>
);
}
// Use memo for performance optimization: Avoid unnecessary re-renders
export default memo(UserProfile);3. State Updates and Re-rendering โ
function Counter() {
const [count, setCount] = useState(0);
const [name, setName] = useState("");
const [history, setHistory] = useState([]);
// State updates trigger re-renders
const increment = () => {
setCount((prevCount) => prevCount + 1); // Use function form to get latest state
// Batch state updates: React merges these updates
setName("Counter");
setHistory((prev) => [...prev, `Count changed to: ${count + 1}`]);
};
const reset = () => {
setCount(0);
setName("");
setHistory([]);
};
console.log("Component re-rendered, count:", count);
return (
<div className="counter">
<h2>Counter: {count}</h2>
<p>Status: {name}</p>
<div className="controls">
<button onClick={increment}>Increment</button>
<button onClick={reset}>Reset</button>
</div>
<div className="history">
<h3>History:</h3>
{history.map((item, index) => (
<p key={index}>{item}</p>
))}
</div>
</div>
);
}React Hooks Detailed โ
Hooks were introduced in React 16.8, allowing you to use state and other React features in function components:
import {
useState,
useEffect,
useContext,
useReducer,
useCallback,
useMemo,
useRef,
} from "react";
// 1. useState - State management
function PersonalInfoForm() {
const [formData, setFormData] = useState({
name: "",
email: "",
phone: "",
age: "",
});
const [errors, setErrors] = useState({});
const handleChange = (field, value) => {
setFormData((prev) => ({
...prev,
[field]: value,
}));
// Clear error for this field
if (errors[field]) {
setErrors((prev) => ({
...prev,
[field]: "",
}));
}
};
return (
<form className="personal-info-form">
<input
type="text"
placeholder="Name"
value={formData.name}
onChange={(e) => handleChange("name", e.target.value)}
className={errors.name ? "error" : ""}
/>
<input
type="email"
placeholder="Email"
value={formData.email}
onChange={(e) => handleChange("email", e.target.value)}
className={errors.email ? "error" : ""}
/>
{/* More input fields... */}
</form>
);
}
// 2. useReducer - Complex state management
const todoReducer = (state, action) => {
switch (action.type) {
case "ADD_TODO":
return {
...state,
todos: [
...state.todos,
{
id: Date.now(),
text: action.payload,
completed: false,
},
],
};
case "TOGGLE_TODO":
return {
...state,
todos: state.todos.map((todo) =>
todo.id === action.payload
? { ...todo, completed: !todo.completed }
: todo
),
};
case "DELETE_TODO":
return {
...state,
todos: state.todos.filter((todo) => todo.id !== action.payload),
};
case "SET_FILTER":
return {
...state,
filter: action.payload,
};
default:
return state;
}
};
function TodoApp() {
const [state, dispatch] = useReducer(todoReducer, {
todos: [],
filter: "ALL", // ALL, ACTIVE, COMPLETED
});
const addTodo = (text) => {
dispatch({ type: "ADD_TODO", payload: text });
};
const toggleTodo = (id) => {
dispatch({ type: "TOGGLE_TODO", payload: id });
};
const deleteTodo = (id) => {
dispatch({ type: "DELETE_TODO", payload: id });
};
const setFilter = (filter) => {
dispatch({ type: "SET_FILTER", payload: filter });
};
const filteredTodos = state.todos.filter((todo) => {
switch (state.filter) {
case "ACTIVE":
return !todo.completed;
case "COMPLETED":
return todo.completed;
default:
return true;
}
});
return (
<div className="todo-app">
<TodoInput onAdd={addTodo} />
<TodoFilter filter={state.filter} onFilterChange={setFilter} />
<TodoList
todos={filteredTodos}
onToggle={toggleTodo}
onDelete={deleteTodo}
/>
</div>
);
}
// 3. useContext - Cross-component state sharing
const ThemeContext = React.createContext();
const UserContext = React.createContext();
function App() {
const [theme, setTheme] = useState("light");
const [user, setUser] = useState(null);
return (
<ThemeContext.Provider value={{ theme, setTheme }}>
<UserContext.Provider value={{ user, setUser }}>
<MainApp />
</UserContext.Provider>
</ThemeContext.Provider>
);
}
function Header() {
const { theme, setTheme } = useContext(ThemeContext);
const { user } = useContext(UserContext);
return (
<header className={`header ${theme}`}>
<h1>My App</h1>
<div className="header-actions">
{user ? <span>Welcome, {user.name}</span> : <button>Login</button>}
<button onClick={() => setTheme(theme === "light" ? "dark" : "light")}>
Toggle Theme
</button>
</div>
</header>
);
}
// 4. useCallback - Performance optimization
function ParentComponent() {
const [count, setCount] = useState(0);
const [name, setName] = useState("");
// Use useCallback to avoid recreating function
const handleIncrement = useCallback(() => {
setCount((prevCount) => prevCount + 1);
}, []); // Empty dependency array means function never recreated
const handleNameChange = useCallback((value) => {
setName(value);
}, []); // Function also never recreated
return (
<div>
<ChildButton onClick={handleIncrement} />
<ChildInput value={name} onChange={handleNameChange} />
<p>Count: {count}</p>
</div>
);
}
// 5. useMemo - Computation result caching
function ExpensiveCalculation({ data }) {
// Use useMemo to cache computation result
const expensiveValue = useMemo(() => {
console.log("Performing complex calculation...");
return data.reduce(
(sum, num) => sum + Math.sqrt(num) * Math.log(num + 1),
0
);
}, [data]); // Only recalculate when data changes
return (
<div>
<p>Computation result: {expensiveValue}</p>
<p>Data length: {data.length}</p>
</div>
);
}
// 6. useRef - Reference DOM elements or persistent values
function InputWithFocus() {
const inputRef = useRef(null);
const renderCountRef = useRef(0);
renderCountRef.current += 1; // Won't trigger re-render
const focusInput = () => {
inputRef.current?.focus();
};
return (
<div>
<input ref={inputRef} type="text" placeholder="Click button to focus" />
<button onClick={focusInput}>Focus Input</button>
<p>Component renders: {renderCountRef.current}</p>
</div>
);
}React's Modern Use Cases โ
1. Single Page Applications (SPA) โ
import {
BrowserRouter as Router,
Routes,
Route,
Link,
useParams,
} from "react-router-dom";
// Route configuration
function App() {
return (
<Router>
<div className="app">
<Navigation />
<Routes>
<Route path="/" element={<HomePage />} />
<Route path="/about" element={<AboutPage />} />
<Route path="/products" element={<ProductsPage />} />
<Route path="/products/:id" element={<ProductDetail />} />
<Route path="/contact" element={<ContactPage />} />
</Routes>
<Footer />
</div>
</Router>
);
}
// Navigation component
function Navigation() {
return (
<nav className="navigation">
<Link to="/" className="nav-brand">
My Website
</Link>
<div className="nav-links">
<Link to="/">Home</Link>
<Link to="/about">About</Link>
<Link to="/products">Products</Link>
<Link to="/contact">Contact</Link>
</div>
</nav>
);
}
// Dynamic route parameters
function ProductDetail() {
const { id } = useParams();
const [product, setProduct] = useState(null);
useEffect(() => {
fetch(`/api/products/${id}`)
.then((res) => res.json())
.then((data) => setProduct(data));
}, [id]);
if (!product) return <div>Loading...</div>;
return (
<div className="product-detail">
<h1>{product.name}</h1>
<p>Price: ${product.price}</p>
<p>{product.description}</p>
</div>
);
}2. Real-time Data Applications โ
import { useState, useEffect } from "react";
function ChatRoom() {
const [messages, setMessages] = useState([]);
const [newMessage, setNewMessage] = useState("");
const [isConnected, setIsConnected] = useState(false);
// WebSocket connection
useEffect(() => {
const ws = new WebSocket("ws://localhost:8080/chat");
ws.onopen = () => {
setIsConnected(true);
console.log("Connected to chat room");
};
ws.onmessage = (event) => {
const message = JSON.parse(event.data);
setMessages((prev) => [...prev, message]);
};
ws.onclose = () => {
setIsConnected(false);
console.log("Disconnected");
};
return () => ws.close();
}, []);
const sendMessage = () => {
if (newMessage.trim() && isConnected) {
const message = {
id: Date.now(),
text: newMessage,
timestamp: new Date().toISOString(),
user: "Current User",
};
// Send message to server
ws.send(JSON.stringify(message));
setNewMessage("");
}
};
return (
<div className="chat-room">
<div className="chat-header">
<h2>Chat Room</h2>
<span
className={`connection-status ${
isConnected ? "connected" : "disconnected"
}`}
>
{isConnected ? "Connected" : "Connecting..."}
</span>
</div>
<div className="messages-container">
{messages.map((message) => (
<div key={message.id} className="message">
<span className="message-user">{message.user}:</span>
<span className="message-text">{message.text}</span>
<span className="message-time">
{new Date(message.timestamp).toLocaleTimeString()}
</span>
</div>
))}
</div>
<div className="message-input">
<input
type="text"
value={newMessage}
onChange={(e) => setNewMessage(e.target.value)}
onKeyPress={(e) => e.key === "Enter" && sendMessage()}
placeholder="Type message..."
disabled={!isConnected}
/>
<button
onClick={sendMessage}
disabled={!isConnected || !newMessage.trim()}
>
Send
</button>
</div>
</div>
);
}Why Choose React? โ
1. Rich Ecosystem โ
- Numerous third-party libraries: React Router, Redux, Material-UI, Ant Design, etc.
- Active community: Stack Overflow, GitHub, Reddit and other platforms have rich resources
- Enterprise-level support: Used by Facebook, Netflix, Airbnb and other large companies
2. Excellent Development Experience โ
// Development tools and debugging
- React Developer Tools (browser extension)
- Complete TypeScript support
- Hot Module Replacement
- Rich error hints and debugging information3. Performance Optimization Capabilities โ
// Multiple performance optimization approaches
- useMemo and useCallback for caching computations and functions
- React.memo to avoid unnecessary component re-renders
- lazy and Suspense for code splitting
- Virtual scrolling for large data lists
- Concurrent Mode for improved rendering performance4. Learning Value and Job Opportunities โ
React is currently one of the most popular frontend frameworks. Mastering React provides developers with excellent job opportunities and career prospects.
Summary โ
React fundamentally changed frontend development by introducing concepts like component-based architecture, virtual DOM, and declarative programming. It's not just a library but a new methodology for thinking about and building user interfaces.
Key Takeaways:
- React is a JavaScript library developed by Facebook for building user interfaces
- Core features include component-based architecture, declarative programming, virtual DOM, and unidirectional data flow
- JSX makes HTML-like syntax possible in JavaScript
- Hooks give function components state management and other React features
- Rich ecosystem, excellent development experience, and broad job prospects
- Understanding React's working principles and best practices is an essential skill for modern frontend development
React's design philosophy has influenced the entire frontend industry's development, with many other frameworks borrowing its core concepts. In the upcoming lessons, we'll dive deeper into various aspects of React, including component development, state management, performance optimization, testing strategies, and more, helping you become an excellent React developer.