Table of Contents
- What is React?
- Setting Up Your React Environment
- Understanding JSX: The Heart of React
- Components: The Building Blocks of React Apps
- Props: Passing Data Between Components
- State: Managing Dynamic Data
- Lifecycle Methods & Hooks: Controlling Component Behavior
- Routing with React Router
- Hands-On Project: Build a Todo App
- Conclusion
- References
What is React? {#what-is-react}
At its core, React is a JavaScript library for building user interfaces. Unlike full frameworks like Angular or Vue, React focuses solely on the “view” layer of the MVC (Model-View-Controller) architecture. This flexibility lets you integrate it with other libraries or existing projects.
Key Concepts of React:
- Component-Based: UIs are built with reusable, independent “components” (e.g., buttons, forms, cards).
- Declarative: Instead of writing step-by-step “how to” code (imperative), you describe “what” the UI should look like, and React handles the “how.”
- Virtual DOM: A lightweight copy of the actual DOM. React updates the Virtual DOM first, then syncs changes to the real DOM (diffing), making apps fast.
Setting Up Your React Environment {#setting-up-your-react-environment}
To start coding React, you’ll need:
- Node.js: A JavaScript runtime (includes npm, a package manager).
- Code Editor:推荐 Visual Studio Code (VS Code) with React extensions (e.g., ESLint, Prettier).
Step 1: Install Node.js
Go to nodejs.org and download the LTS version. Verify installation by running these commands in your terminal:
node -v # Should show a version (e.g., v18.17.0)
npm -v # Should show a version (e.g., 9.6.7)
Step 2: Create a React App
Use create-react-app (a tool by Facebook) to bootstrap a new React project. Run:
npx create-react-app my-first-react-app
npx(Node Package Runner) avoids installingcreate-react-appglobally.my-first-react-appis your project name (change it to something fun!).
Step 3: Run the App
Navigate into your project folder and start the development server:
cd my-first-react-app
npm start
Your app will open at http://localhost:3000 with a default React page.
Project Structure Explained
Let’s explore the key files/folders in my-first-react-app:
public/: Static files (HTML, images). Theindex.htmlis the entry point (React injects the app here).src/: Your React code lives here.index.js: Renders the root component (App.js) into the DOM.App.js: The main component (you’ll edit this!).
package.json: Lists dependencies and scripts (e.g.,npm start).
Understanding JSX: The Heart of React {#understanding-jsx}
JSX (JavaScript XML) is a syntax extension for JavaScript that lets you write HTML-like code in React. It’s not HTML, but a way to describe UI elements.
Why JSX?
Without JSX, creating React elements would require verbose code like:
React.createElement("h1", { className: "greeting" }, "Hello, React!");
With JSX, it’s cleaner:
<h1 className="greeting">Hello, React!</h1>
Key JSX Rules
-
One Root Element: JSX expressions must have a single parent (use
<div>,<React.Fragment>, or shorthand<>).// ❌ Invalid (two roots) <h1>Hello</h1> <p>World</p> // ✅ Valid (single root with fragment) <> <h1>Hello</h1> <p>World</p> </> -
Class vs. className: Use
classNameinstead ofclass(sinceclassis a reserved word in JavaScript).<div className="box">This is a box</div> -
Self-Closing Tags: Tags like
<img>,<input>, or custom components must close with/(e.g.,<img src="logo.png" />). -
Embed JavaScript: Use curly braces
{}to inject variables or expressions into JSX.const name = "Alice"; <p>Hello, {name}!</p> // Renders: "Hello, Alice!" -
Conditional Rendering: Use ternary operators or logical
&&inside{}.const isLoggedIn = true; <div>{isLoggedIn ? <p>Welcome back!</p> : <p>Please log in.</p>}</div>
Components: The Building Blocks of React Apps {#components-the-building-blocks-of-react-apps}
Components are reusable, self-contained pieces of UI. There are two types: Functional Components (modern, preferred) and Class Components (older, rarely used today).
Functional Components
A function that returns JSX. Simple, lightweight, and works with hooks (more on hooks later).
Example: A Greeting Component
Create a new file src/components/Greeting.js:
function Greeting() {
return <h1>Hello, React Learner!</h1>;
}
export default Greeting; // Export to use in other files
Import and use it in App.js:
import Greeting from './components/Greeting';
function App() {
return (
<div className="App">
<Greeting /> {/* Renders the Greeting component */}
</div>
);
}
export default App;
Class Components (Legacy)
Before hooks, components were classes extending React.Component. They use render() to return JSX.
Example (for reference only—use functional components!):
import React from 'react';
class Greeting extends React.Component {
render() {
return <h1>Hello, React Learner!</h1>;
}
}
export default Greeting;
Props: Passing Data Between Components {#props-passing-data-between-components}
Props (short for “properties”) let you pass data from a parent component to a child component. They are read-only (children can’t modify props).
Example: Passing a “Name” Prop
Update Greeting.js to accept a name prop:
function Greeting(props) {
return <h1>Hello, {props.name}!</h1>;
}
export default Greeting;
In App.js, pass the name prop when using Greeting:
<Greeting name="Bob" /> {/* Renders: "Hello, Bob!" */}
<Greeting name="Alice" /> {/* Renders: "Hello, Alice!" */}
Destructuring Props
Simplify code by destructuring props directly in the function parameters:
function Greeting({ name }) { // Destructure name from props
return <h1>Hello, {name}!</h1>;
}
Default Props
Set fallback values for props if none are passed:
function Greeting({ name = "Guest" }) { // Default to "Guest"
return <h1>Hello, {name}!</h1>;
}
// Usage: <Greeting /> renders "Hello, Guest!"
State: Managing Dynamic Data {#state-managing-dynamic-data}
State is data that changes over time (e.g., form inputs, counters, API data). Unlike props (passed from parents), state is managed internally by a component and can be updated.
Using useState Hook
Hooks are functions that let you use state and lifecycle features in functional components. useState is the most basic hook for state management.
Example: A Counter Component
Create src/components/Counter.js:
import { useState } from 'react'; // Import useState
function Counter() {
// Initialize state: [currentState, setState] = useState(initialValue)
const [count, setCount] = useState(0);
return (
<div>
<p>You clicked {count} times</p>
<button onClick={() => setCount(count + 1)}>
Click me
</button>
</div>
);
}
export default Counter;
count: The current state value (starts at 0).setCount: A function to updatecount(never modify state directly withcount++—always use the setter!).
State Updates Are Asynchronous
setCount doesn’t update count immediately. If you need to use the previous state, pass a function to setCount:
// ❌ Risky: count might not be updated yet
<button onClick={() => setCount(count + 1)}>
// ✅ Safe: uses the latest state
<button onClick={() => setCount(prevCount => prevCount + 1)}>
Form Input State Example
Track input values with state:
function NameInput() {
const [name, setName] = useState("");
return (
<div>
<input
type="text"
value={name} // "Controlled component": value tied to state
onChange={(e) => setName(e.target.value)} // Update state on input
/>
<p>Hello, {name}!</p>
</div>
);
}
Lifecycle Methods & Hooks: Controlling Component Behavior {#lifecycle-methods—hooks-controlling-component-behavior}
Components have “lifecycle” events: mounting (created), updating (state/props change), and unmounting (removed). With class components, you used methods like componentDidMount(). With functional components, we use hooks like useEffect.
useEffect: Side Effects
useEffect lets you run code after render (e.g., data fetching, subscriptions, DOM updates). It replaces class lifecycle methods.
Syntax:
useEffect(() => {
// Code to run (side effect)
return () => {
// Cleanup code (runs before unmounting/updating)
};
}, [dependencies]); // Run effect only when dependencies change
Example 1: Run on Mount (like componentDidMount)
Empty dependency array [] runs the effect once, after the component mounts:
useEffect(() => {
console.log("Component mounted!");
}, []); // Empty array = run once
Example 2: Run on Update (like componentDidUpdate)
Include dependencies to run the effect when they change:
const [count, setCount] = useState(0);
useEffect(() => {
console.log(`Count updated to ${count}`);
}, [count]); // Runs when count changes
Example 3: Cleanup (like componentWillUnmount)
Return a cleanup function to avoid memory leaks (e.g., cancel subscriptions):
useEffect(() => {
const timer = setInterval(() => {
setCount(prev => prev + 1);
}, 1000);
return () => clearInterval(timer); // Cleanup: stop timer on unmount
}, []);
Routing with React Router {#routing-with-react-router}
Single-Page Apps (SPAs) use client-side routing (no full page reloads). react-router-dom is the standard library for this.
Step 1: Install React Router
npm install react-router-dom
Step 2: Basic Routing Setup
Update src/index.js to wrap your app with BrowserRouter (the root router):
import { BrowserRouter } from 'react-router-dom';
ReactDOM.createRoot(document.getElementById('root')).render(
<BrowserRouter>
<App />
</BrowserRouter>
);
Step 3: Create Pages & Routes
Add three pages: Home, About, and Contact.
1. Create Page Components
-
src/pages/Home.js:function Home() { return <h1>Home Page</h1>; } export default Home; -
src/pages/About.jsandsrc/pages/Contact.js(similar structure).
2. Set Up Routes in App.js
Use Routes and Route to define which component renders at which URL:
import { Routes, Route, Link } from 'react-router-dom';
import Home from './pages/Home';
import About from './pages/About';
import Contact from './pages/Contact';
function App() {
return (
<div>
{/* Navigation Bar */}
<nav>
<Link to="/">Home</Link> |
<Link to="/about">About</Link> |
<Link to="/contact">Contact</Link>
</nav>
{/* Routes */}
<Routes>
<Route path="/" element={<Home />} /> {/* Home at / */}
<Route path="/about" element={<About />} /> {/* About at /about */}
<Route path="/contact" element={<Contact />} /> {/* Contact at /contact */}
</Routes>
</div>
);
}
Link: Replaces<a>tags to avoid full page reloads.Route:pathis the URL,elementis the component to render.
Hands-On Project: Build a Todo App {#hands-on-project-build-a-todo-app}
Let’s combine everything to build a todo list app with:
- Adding todos (form state).
- Displaying todos (props).
- Deleting todos (state updates).
Step 1: Project Setup
Create these files in src/components:
TodoForm.js: Input form to add todos.TodoList.js: Displays all todos.TodoItem.js: Individual todo item (with delete button).
Step 2: TodoForm.js
Handles input and adds todos to the list:
import { useState } from 'react';
function TodoForm({ addTodo }) { // addTodo is a prop from parent
const [todoText, setTodoText] = useState("");
const handleSubmit = (e) => {
e.preventDefault(); // Prevent default form submission
if (todoText.trim()) { // Don't add empty todos
addTodo(todoText); // Call parent's addTodo function
setTodoText(""); // Clear input
}
};
return (
<form onSubmit={handleSubmit}>
<input
type="text"
value={todoText}
onChange={(e) => setTodoText(e.target.value)}
placeholder="Add a new todo..."
/>
<button type="submit">Add</button>
</form>
);
}
export default TodoForm;
Step 3: TodoItem.js
Displays a single todo and a delete button:
function TodoItem({ todo, onDelete }) { // todo (text) and onDelete (function) from parent
return (
<div>
<span>{todo}</span>
<button onClick={() => onDelete(todo)}>×</button>
</div>
);
}
export default TodoItem;
Step 4: TodoList.js
Renders all todos by mapping over the todo list:
import TodoItem from './TodoItem';
function TodoList({ todos, onDelete }) { // todos array and onDelete from parent
return (
<div>
{todos.map((todo, index) => (
<TodoItem
key={index} // Unique key for list items (use IDs in real apps)
todo={todo}
onDelete={onDelete}
/>
))}
</div>
);
}
export default TodoList;
Step 5: App.js (Put It All Together)
Manage the todos state and pass functions/props to child components:
import { useState } from 'react';
import TodoForm from './components/TodoForm';
import TodoList from './components/TodoList';
function App() {
const [todos, setTodos] = useState([]); // todos is an empty array
// Add a new todo to the array
const addTodo = (text) => {
setTodos([...todos, text]); // Spread existing todos and add new one
};
// Delete a todo by filtering it out
const deleteTodo = (textToDelete) => {
setTodos(todos.filter(todo => todo !== textToDelete));
};
return (
<div className="App">
<h1>Todo App</h1>
<TodoForm addTodo={addTodo} />
<TodoList todos={todos} onDelete={deleteTodo} />
</div>
);
}
export default App;
Run the App!
Start the server with npm start. You can now add todos, see them listed, and delete them. Congrats—you built a React app!
Conclusion {#conclusion}
You’ve now mastered React basics:
- JSX for writing UI.
- Components and props for reusability.
- State and
useStatefor dynamic data. useEffectfor side effects.- Routing with React Router.
- Building a todo app with all these concepts!
React is a journey—keep practicing by adding features to your todo app (e.g., edit todos, mark as complete) or building new projects (weather app, blog). The more you code, the more confident you’ll become.
References {#references}
- React Official Documentation – Best for learning hooks, components, and advanced topics.
- React Router Documentation – Routing deep dive.
- MDN Web Docs – Brush up on JavaScript (essential for React!).
- freeCodeCamp React Tutorials – Hands-on exercises.
- Kent C. Dodds’ Blog – Expert insights on React hooks and patterns.
Happy coding—you’re on your way to React hero status! 🚀