React is one of the most widely used libraries for building modern user interfaces.
Whether you're building a small interactive website, a dashboard, an e-commerce application, or a complex web platform, React provides a component-based approach that helps you build reusable, maintainable UI.
But learning React isn't just about memorizing hooks or writing JSX.
To understand React properly, you need to understand how components work, how data flows through an application, how state changes the UI, and how React manages rendering.
In this guide, we'll explore the most important React concepts — from the fundamentals to advanced patterns — using practical examples.
This article is designed as a roadmap and reference for developers learning React.
Table of Contents
- What Is React?
- Why React?
- Declarative vs. Imperative Programming
- Creating a React Application
- Understanding JSX
- Components
- Props
- State
- Events
- Conditional Rendering
- Rendering Lists and Keys
- Component Composition
- State Management and Data Flow
- React Hooks
- useState
- useEffect
- useRef
- useContext
- useReducer
- Custom Hooks
- Forms in React
- API Requests
- React Router
- State Management Libraries
- React Performance
- React Internals
- Virtual DOM and Reconciliation
- React Fiber
- React 19
- Server Components
- Error Boundaries and Suspense
- Testing React Applications
- React Best Practices
- Common React Mistakes
- React Learning Roadmap
- Final Thoughts
1. What Is React?
React is a JavaScript library for building user interfaces.
It was developed at Facebook, now Meta, and is maintained by Meta and the React community.
React helps developers build interfaces using small, reusable pieces called components.
Instead of manually manipulating the DOM every time something changes, developers describe what the UI should look like based on the current data.
React then manages updating the interface.
For example, imagine a dashboard containing:
- A navigation bar
- A sidebar
- A user profile
- A notification panel
- A list of products
Each section can be represented by a separate component.
function App() { return ( <div> <Navbar /> <Sidebar /> <Dashboard /> </div> ); } This approach makes applications easier to organize, reuse, and maintain.
2. Why React?
Before React, developers often used JavaScript to manipulate the DOM directly.
const button = document.querySelector("button"); button.addEventListener("click", () => { document.querySelector("h1").textContent = "Hello!"; }); This works, but as an application grows, manually managing DOM changes can become difficult.
React introduces a different approach.
Instead of telling the browser exactly how to update the DOM, we describe the UI based on the current state.
function App() { const [name, setName] = React.useState("John"); return ( <div> <h1>Hello, {name}</h1> <button onClick={() => setName("Sarah")}> Change Name </button> </div> ); } When the state changes, React updates the relevant UI.
Key advantages
- Component-based architecture
- Reusable UI
- Declarative rendering
- Efficient updates
- Strong ecosystem
- Large developer community
- Integration with modern frontend tools
React is a library, not a complete framework by itself. Routing, data fetching strategies, and other application-level features may come from additional libraries or frameworks.
3. Declarative vs. Imperative Programming
This is one of the most important concepts in React.
Imperative programming
Imperative programming describes how to perform a task step by step.
const heading = document.createElement("h1"); heading.textContent = "Hello React"; document.body.appendChild(heading); We explicitly tell the browser:
- Create an element.
- Set its text.
- Add it to the document.
Declarative programming
Declarative programming describes what the UI should look like.
function App() { return <h1>Hello React</h1>; } React handles the necessary DOM operations.
The difference becomes especially important when data changes.
With React, you generally update the state and let React determine how the UI should change.
4. Creating a React Application
A common way to start a React project is with Vite.
Vite provides a development server and build tooling for modern frontend applications.
Create a project:
npm create vite@latest my-react-app Choose React and JavaScript or TypeScript.
Then:
cd my-react-app npm install npm run dev For a React + TypeScript project, choose the TypeScript template.
A typical project structure:
my-react-app/ ├── public/ ├── src/ │ ├── assets/ │ ├── components/ │ ├── App.tsx │ ├── main.tsx │ └── index.css ├── package.json └── vite.config.ts The exact structure may vary depending on the template.
What is main.tsx?
This is commonly the entry point of a Vite React application.
import { StrictMode } from "react"; import { createRoot } from "react-dom/client"; import App from "./App"; createRoot(document.getElementById("root")!).render( <StrictMode> <App /> </StrictMode> ); React renders the App component inside the root DOM element.
5. Understanding JSX
JSX stands for JavaScript XML.
It allows developers to write HTML-like syntax inside JavaScript.
const element = <h1>Hello React</h1>; JSX is not HTML, even though it looks similar.
It is transformed into JavaScript by the build system.
JSX expressions
You can use JavaScript expressions inside curly braces.
function App() { const name = "John"; return <h1>Hello, {name}</h1>; } Output:
Hello, John You can also use calculations:
<p>{10 + 20}</p> JSX rules
Return a single parent element
Incorrect:
return ( <h1>Hello</h1> <p>Welcome</p> ); Correct:
return ( <div> <h1>Hello</h1> <p>Welcome</p> </div> ); Or use a Fragment:
return ( <> <h1>Hello</h1> <p>Welcome</p> </> ); Use className instead of class
<div className="container"> Hello </div> Close elements
<img src="/logo.png" alt="Logo" /> <input /> Use camelCase for many JSX attributes
<button onClick={handleClick}> Click me </button> 6. Components
Components are the building blocks of React applications.
A component is usually a JavaScript function that returns React elements.
function Welcome() { return <h1>Welcome to React</h1>; } Use it inside another component:
function App() { return ( <div> <Welcome /> <Welcome /> </div> ); } The Welcome component can be reused wherever needed.
Component naming
React component names must start with an uppercase letter.
Correct:
function UserCard() { return <h2>User Card</h2>; } Incorrect:
function userCard() { return <h2>User Card</h2>; } React treats lowercase JSX names as HTML elements.
Components should be pure
A component should generally return the same UI for the same inputs.
Avoid changing external values directly during rendering.
function Greeting({ name }) { return <h1>Hello, {name}</h1>; } React components should not perform side effects during render.
7. Props
Props allow components to receive data from their parent.
Think of props as the inputs of a component.
function UserCard({ name, age }) { return ( <div> <h2>{name}</h2> <p>Age: {age}</p> </div> ); } Usage:
function App() { return ( <UserCard name="John" age={25} /> ); } The parent passes data to the child.
Important: Props are read-only
A child component should not directly modify its props.
Instead, the parent controls the data and can pass callback functions when the child needs to request a change.
Props with TypeScript
interface UserCardProps { name: string; age: number; } function UserCard({ name, age }: UserCardProps) { return ( <div> <h2>{name}</h2> <p>{age}</p> </div> ); } TypeScript helps ensure the component receives the correct data.
8. State
State is data that a component remembers between renders.
Unlike ordinary local variables, updating state causes React to render the component again.
import { useState } from "react"; function Counter() { const [count, setCount] = useState(0); return ( <div> <h1>{count}</h1> <button onClick={() => setCount(count + 1)}> Increment </button> </div> ); } Here:
-
countis the current state value. -
setCountupdates the state. -
0is the initial value.
Why not use a normal variable?
function Counter() { let count = 0; function increment() { count++; console.log(count); } return <button onClick={increment}>{count}</button>; } This variable does not persist correctly across renders and does not tell React to update the UI.
State solves that problem.
State updates
React state is a snapshot for a particular render.
When updating state based on its previous value, use the functional updater form:
setCount((previousCount) => previousCount + 1); This is especially useful when updates depend on the previous state.
9. Events
React supports event handling using JSX props.
function App() { function handleClick() { console.log("Button clicked"); } return ( <button onClick={handleClick}> Click me </button> ); } Notice that we pass the function:
onClick={handleClick} We don't execute it during render:
// Incorrect onClick={handleClick()} The incorrect version calls the function immediately.
Passing arguments
function App() { function greet(name) { console.log(`Hello, ${name}`); } return ( <button onClick={() => greet("John")}> Greet </button> ); } Event objects
function App() { function handleClick(event) { console.log(event.target); } return ( <button onClick={handleClick}> Click me </button> ); } React events provide information about the interaction.
In TypeScript, event handlers can be typed with React event types.
10. Conditional Rendering
React allows you to render different UI depending on a condition.
Using if
function Greeting({ isLoggedIn }) { if (isLoggedIn) { return <h1>Welcome back!</h1>; } return <h1>Please log in.</h1>; } Using the ternary operator
function Greeting({ isLoggedIn }) { return ( <h1> {isLoggedIn ? "Welcome back!" : "Please log in."} </h1> ); } Using logical AND
function Notifications({ count }) { return ( <div> {count > 0 && <p>You have notifications.</p>} </div> ); } Be careful when using && with numbers:
{count && <p>Notifications</p>} If count is 0, React may render 0.
A safer expression:
{count > 0 && <p>Notifications</p>} 11. Rendering Lists and Keys
React can render arrays of data using JavaScript's map() method.
function App() { const users = ["John", "Sarah", "Alex"]; return ( <ul> {users.map((user) => ( <li key={user}> {user} </li> ))} </ul> ); } Why do keys matter?
Keys help React identify which items changed, were added, or were removed.
Use stable, unique identifiers whenever possible.
const users = [ { id: 1, name: "John" }, { id: 2, name: "Sarah" }, ]; {users.map((user) => ( <UserCard key={user.id} name={user.name} /> ))} Avoid using array indexes as keys when the list can be reordered, inserted into, or deleted from.
Keys are not passed to the component as props.
12. Component Composition
Composition means building complex UI by combining smaller components.
Instead of creating one huge component, break the interface into reusable pieces.
function Header() { return <header>My Website</header>; } function Sidebar() { return <aside>Navigation</aside>; } function Content() { return <main>Main Content</main>; } function App() { return ( <> <Header /> <div className="layout"> <Sidebar /> <Content /> </div> </> ); } Composition is one of React's most important architectural ideas.
The children prop
function Card({ children }) { return ( <div className="card"> {children} </div> ); } Usage:
<Card> <h2>Profile</h2> <p>User information</p> </Card> This makes components flexible and reusable.
13. State Management and Data Flow
React follows a pattern commonly called one-way data flow.
Data usually flows from parent components to child components through props.
Parent ↓ Props Child ↓ Props Grandchild When a child needs to request a change, the parent can pass a callback.
function Parent() { const [message, setMessage] = useState("Hello"); return ( <Child message={message} onChangeMessage={setMessage} /> ); } function Child({ message, onChangeMessage }) { return ( <div> <p>{message}</p> <button onClick={() => onChangeMessage("Updated!")}> Update </button> </div> ); } Lifting state up
When multiple components need the same state, move it to their nearest common parent.
This is called lifting state up.
It helps keep shared data consistent.
14. React Hooks
Hooks allow function components to use React features such as state, context, refs, and effects.
Common hooks include:
| Hook | Purpose |
|---|---|
useState | Local component state |
useEffect | Synchronization with external systems |
useRef | Persistent values and DOM references |
useContext | Access shared context |
useReducer | Complex state logic |
useMemo | Cache a calculation |
useCallback | Cache a function definition |
useId | Generate IDs for accessibility |
useTransition | Mark updates as non-blocking |
useDeferredValue | Defer a non-urgent value |
useSyncExternalStore | Subscribe to external stores |
Rules of Hooks
Hooks must follow specific rules:
- Call hooks only at the top level.
- Don't call hooks inside conditions or loops.
- Call hooks from React components or custom hooks.
- Don't call hooks from ordinary JavaScript functions.
Incorrect:
if (isLoggedIn) { useState(true); } Correct:
const [isLoggedIn, setIsLoggedIn] = useState(false); Hooks must be called in the same order on every render.
15. useState
useState allows a component to store and update state.
import { useState } from "react"; function Counter() { const [count, setCount] = useState(0); return ( <button onClick={() => setCount(count + 1)}Source:https://dev.to/hamedfarazi/react-explained-the-complete-guide-2llb Related posts
Playwright Email Tests Need an Inbox Lease
