Complete guide to building applications in React.
- Introduction to React
- Tech Stack & Prerequisites
- Quick Start
- Creating a New React App
- React App Usage
- Base React App
- React Component Types
- Introduction Project
- CSS Modules for Styling
- React Fragments
- Overview of React Hooks
- State Management
- React Side Effects
- Performance Optimization
- Sending HTTP Requests
- All React Demo Projects
React is a JavaScript library for building user interfaces. It is developed and maintained by Meta (Facebook) and is widely used for creating fast, scalable, and interactive web applications.
Key Features of React
✅ Component-Based Architecture – Improve maintainability with reusable components.
✅ Declarative UI – Describe how the UI should look, and React updates it efficiently.
✅ Virtual DOM – Optimizes performance by updating only necessary parts of the UI, which allows for fast rendering.
✅ Unidirectional Data Flow – Data flows from parent to child components, ensuring predictable state management.
✅ Hooks & Functional Components – Simplifies state and side-effects management without needing class components.
✅ Strong Ecosystem – Works well with libraries like React Router, Redux, and more, with strong community support and widespread adoption.
| Technology | Version | Description |
|---|---|---|
| React | 19.x | UI library for building component-based interfaces |
| React DOM | 19.x | React rendering for web browsers |
| React Scripts | 5.0.1 | Create React App build tooling |
| React Router DOM | 7.x | Client-side routing for React applications |
| Redux Toolkit | 2.x | State management with modern Redux patterns |
| Next.js | 16.x | React framework for server-side rendering |
- Node.js (v18 or higher recommended)
- npm (v9 or higher) or yarn
- Basic knowledge of JavaScript (ES6+)
- Familiarity with HTML and CSS
- Code editor (VS Code recommended)
- Browser with React DevTools extension
- Git for version control
Clone the repository and navigate to any project folder:
git clone https://github.com/your-username/complete-react-guide.git
cd complete-react-guide/base-react-appInstall dependencies and start the development server:
npm install
npm startThe app will open at http://localhost:3000.
Tip
Each project folder contains its own readme.md with specific instructions and documentation.
Instructions for creating a new React app using Node Package Manager (
npm).
Note
All examples in this section can be found in 📁 new-react-app
Node Package Manager (npm) is a package manager for JavaScript that helps developers install, manage, and share dependencies.
It is the default package manager for Node.js and is widely used in web development.
This includes React applications which rely on various dependencies (react and react-dom) and other libraries for state management, routing, UI components, and more. npm helps in managing these dependencies efficiently.
In a React environment managed by npm, the node_modules directory contains all installed npm packages used by the app.
The npm command for creating a new React app is:
npx create-react-app my-new-app
npx
- Package runner that comes with npm 5.2+ and higher.
- Runs the
create-react-apppackage without installing it globally.
create-react-app
- Tool provided by the React team to quickly scaffold a React project with a pre-configured setup.
my-new-app
- Name of the new project folder. Replace
my-new-appwith desired project name.
my-new-app/
├── public/
│ ├── favicon.ico
│ ├── index.html
│ ├── logo192.png
│ ├── logo512.png
│ ├── manifest.json
│ └── robots.txt
├── src/
│ ├── App.css
│ ├── App.js
│ ├── App.test.js
│ ├── index.css
│ ├── index.js
│ ├── logo.svg
│ ├── reportWebVitals.js
│ └── setupTests.js
├── .gitignore
├── package.json
└── README.md
public/
- Contains static assets and the root HTML file for the app.
index.html- Main HTML file where the React app is mounted.
- The
<div id="root"></div>element acts as the entry point for React to inject the app. - You can add meta tags, external scripts, or other HTML configurations here.
logo192.pngandlogo512.png- Logos displaying the specific React symbol (these are usually discarded).
favicon.icoandmanifest.json- Used to provide metadata for the app.
- The
faviconis used as the small icon displayed in a browser tab.
robots.txt- Tells search engine crawlers which URLs the crawler can access on your site.
Tip
📌 Check out the project documentation for information on the use of robots.txt.
src/
- Contains all the main application logic and components.
index.js- Entry point of the React app.
- Renders the
<App />component into the DOM root element.
index.css- Global CSS styles applied across the app.
- Imported into the
index.jsfile:import './index.css';.
App.js- The root React component.
- Defines the main structure of the app by combining child components.
App.css- Styles specific to the
App.jscomponent. - Used in
App.jscomponent with theimportstatement:import './App.css';.
- Styles specific to the
App.test.js- Contains test cases for the App component using tools like Jest or React Testing Library.
reportWebVitals.js- Used to measure performance metrics of the app.
setupTests.js- Allows configuration of testing environment before any tests are run.
- Commonly used with testing libraries like Jest and React Testing Library.
package.json
- Contains metadata about the app and its dependencies.
.gitignore
- Configuration file that specifies which files and directories Git should ignore in version control.
- These often include
node_modules,.DS_Store, production files, etc.
README.md
- A markdown document that provides essential information about the project.
- Typically the first thing users or collaborators see when they visit the repository on platforms like GitHub.
Usage for setting up, installing, and managing the React app environment and dependencies is outlined in the React application usage documentation.
React application used as the base structure for all projects in this guide.
Note
All examples in this section can be found in 📁 base-react-app
base-react-app/
├── public/
├── index.html
├── favicon.ico
├── manifest.json
└── robots.txt
├── src/
├── assets/
| ├── images/
| | ├── basic.jpg
├── components/
| ├── UI/
| | ├── Card.css
| | ├── Card.js
| ├── Footer.css
| ├── Footer.js
| ├── Header.css
| ├── Header.js
├── App.js
├── index.css
├── index.js
├── .gitignore
├── package.json
├── readme.md
The index.js file:
// import React from 'react';
import ReactDOM from 'react-dom/client';
import './index.css';
import App from './App';
const root = ReactDOM.createRoot(document.getElementById('root'));
root.render(<App />);// import React from 'react';
- Imports the core React library, which is needed to use JSX (JavaScript XML) and create React components.
- Starting from release 17, however, you no longer need this statement.
import ReactDOM from 'react-dom/client';
ReactDOMis a library that interacts with the DOM to render React components.react-dom/clientis a new way (starting from React 18) to manage rendering in React apps, replacingReactDOM.render.
import './index.css';
- Imports the global CSS file for the app.
import App from './App';
- Imports the
Appcomponent fromApp.js, which serves as the root component of the application. - The
Appcomponent is typically where the main structure and logic of the app reside.
const root = ReactDOM.createRoot(document.getElementById('root'));
- This selects the root DOM element with the
id="root"(defined inpublic/index.html) and creates a React root usingReactDOM.createRoot. - The
rootserves as the entry point for the React application, allowing React to manage the DOM within this element. - In the
index.htmlfile, this is the target DOM element where the entire React app will be mounted:<div id="root"></div>
root.render(<App />);
- Renders the
Appcomponent inside therootelement in the DOM. - The
<App />syntax is JSX, representing a React component.
The summary, the index.js component:
- Sets up the environment.
- Renders the top-level
Appcomponent into therootDOM element.
The App.js file:
function App() {
return (
<div>
<h2>Let's get started!</h2>
</div>
);
}
export default App;function App()
- Defines a functional component called
App. - A functional component is one of the simplest ways to define a React component. It is essentially a JavaScript function that returns JSX (HTML-like syntax).
return ( ... )
- The
returnstatement specifies what theAppcomponent renders on the screen. - In this case, it returns a
<div>element containing an<h2>element.
<div> and <h2>
- These are JSX elements that look similar to HTML but are actually JavaScript objects under the hood.
- JSX allows you to write markup directly within your JavaScript code, which is then transformed into React elements during compilation.
export default App;
- This exports the
Appcomponent as the default export of the file. - Allows other files to import
App(inindex.jsas importAppfrom'./App';) and use it in the application. - In a larger app, the
Appcomponent would usually serve as the container for other components, managing and rendering their content.
In summary, the App.js component:
- Defines a simple functional React component.
- Renders an HTML structure using JSX.
- Is exported for use as the root component of the app.
Tip
Check out the React app usage documentation for information on basic app usage in this project.
A Look at function and class component definitions.
Note
All examples in this section can be found in 📁 function-class-components
Overview:
Function components are the most common component type used in modern React development.
Functional components are often referred to as stateless components because they did not have built-in state management before React Hooks were introduced.
With the introduction of React Hooks, however, functional components can now manage state.
Functional components, at their core, are JavaScript functions that accept props and return JSX, which is a syntax extension that allows you to write HTML-like structures within JavaScript.
Example:
function MyFunctionalComponent(props) {
return (
<div>
<h2>Hello, Welcome to my Functional Component!</h2>
<p>{props.text}</p>
</div>
);
}
export default MyFunctionalComponent;- Defines a functional component using the
functionkeyword. - Accepts
propsfor any data from the parent component that uses it (accessprops.textin this case). - The
export defaultstatement makes this component available for import in other files of the project.
Overview:
Class components are the "traditional" way of creating React components, emphasizing the used of ES6 class definitions.
React class components extend the React.Component class and provide methods for managing state, lifecycle events, and more.
They are becoming less common in favor of function components and hooks, but can still be useful in certain situations.
Example:
import React, { Component } from 'react';
// Alternatively, `extends React.Component` with only importing `React`
class MyClassComponent extends Component {
render() {
return (
<div>
<h2>Hello, Welcome to my Class Component!</h2>
<p>{this.props.text}</p>
</div>
);
}
}
export default MyClassComponent;- The component is defined as a class that extends
React.Component. this.propsis used to access thepropspassed to the component from theAppcomponent.- The
render()method is required in class components to return the JSX to be rendered.
| Feature | Class Components | Function Components |
|---|---|---|
| Syntax | ES6 classes | Functions |
| State Management | this.state and this.setState() |
useState Hook |
| Lifecycle Methods | Separate methods (componentDidMount) |
useEffect Hook |
| Code Complexity | More verbose | Simpler and concise |
| Performance | Slightly heavier | Lightweight |
Functional components are the modern standard, and the preferred way for writing React components. They are lightweight, easy to understand, and powerful when combined with React Hooks.
Class components are now less common but remain a valuable part of React's history and are still widely used in older React applications.
Intro to getting started with React apps - a simple first project.
Note
All examples in this section can be found in 📁 introduction-project
introduction-project/
├── public/
├── index.html
├── favicon.ico
├── manifest.json
└── robots.txt
├── src/
├── assets/
| ├── images/
| | ├── ui-1.png
| | ├── ui-2.png
├── components/
| ├── Backdrop.js
| ├── Modal.js
| ├── Todo.js
├── App.js
├── index.css
├── index.js
├── .gitignore
├── package.json
├── readme.md
Note
This section does not cover all specific code blocks in index.js and App.js. Check out the 📁 base-react-app for information on code not covered in this section.
The Backdrop.js File:
function Backdrop(props) {
return <div className='backdrop' onClick={props.onClick} />;
}
export default Backdrop;Key Points:
- This component renders a
divwith a class ofbackdrop.classNameis the attribute used to assign CSS classes to elements in JSX. It is the equivalent of theclassattribute in HTML.
- It takes a prop called
onClick, which is a function. - When the
Backdropis clicked, it calls theonClickfunction passed from the parent component. - The
Backdropcomponent, in this example, is used to darken the screen background when a modal is displayed.
The Modal.js File:
function Modal(props) {
return (
<div className='modal'>
<p>{props.text}</p>
<button className='btn btn--alt' onClick={props.onClose}>
Cancel
</button>
<button className='btn' onClick={props.onClose}>
Confirm
</button>
</div>
);
}
export default Modal;Key Points:
- Renders a
divwith a class ofmodal. - Contains a paragraph displaying the
textprop, and two buttons ("Cancel" and "Confirm"), both of which execute theonClosefunction passed as a prop when clicked.
The Todo.js File:
import { useState } from 'react';
import Backdrop from './Backdrop';
import Modal from './Modal';
function Todo(props) {
const [showModal, setShowModal] = useState();
function showModalHandler() {
setShowModal(true);
}
function closeModalHandler() {
setShowModal(false);
}
return (
<div className='card'>
<h2>{props.text}</h2>
<div className='actions'>
<button className='btn' onClick={showModalHandler}>
Delete
</button>
</div>
{showModal && <Backdrop onClick={closeModalHandler} />}
{showModal && <Modal text='Are you sure?' onClose={closeModalHandler} />}
</div>
);
}
export default Todo;Key Points:
- Imports
ModalandBackdropcomponents. - Imports the React
usStatehook, which is used to manage and track state in functional components. - In this example,
usStateis used to manage theshowModalvariable. - Renders a
cardwith a title (props.text) and a "Delete" button. - Clicking the "Delete" button triggers the
showModalHandler, settingshowModaltotruewith:Backdropdisplayed - clicking it callscloseModalHandlerto hide the modal.Modaldisplayed, asking the user for confirmation. Clicking either "Cancel" or "Confirm" also callscloseModalHandler.
Tip
Check out the 📁 state-management section for more information on state usage in React applications.
The App.js File:
import Todo from './components/Todo';
function App() {
return (
<div>
<h1>React Todo List</h1>
<Todo text='Learn React' />
<Todo text='Learn React Hooks' />
<Todo text='Learn React Router' />
</div>
);
}
export default App;- Imports the
Todocomponent. - Renders the title "React Todo List" and a three
Todocomponents.
Note
All examples in this section can be found in 📁 using-css-modules
In React applications, a regular CSS file (.css) will apply styles globally to the entire component.
✅ Useful for global styles, resets, and shared styling.
🚨 Can lead to style conflicts if multiple components have the same class names.
Example Case Using Basic CSS Styles:
The Header.css file:
.header {
padding: 2rem;
display: flex;
flex-direction: column;
justify-content: center;
align-items: center;
margin-bottom: 3rem;
text-align: center;
}
.header h1 {
margin: 0;
font-size: 1.5rem;
}
.header p {
margin: 0;
}The Header.js file:
import React from 'react';
import './Header.css'; // Importing Basic CSS Stylesheet
function Header() {
return (
<header className='header'>
<h1>Top Books</h1>
<p>Curated list of top-selling books</p>
</header>
);
}
export default Header;- 💡 In React, the
classNameproperty is used to assign a class name.- This is equivalent to the
classproperty in HTML elements. - Using basic CSS files, a string defining the class name is used.
- This is equivalent to the
CSS Modules scope CSS styles to a specific component, preventing style conflicts in your project.
✅ Styles are locally scoped to a specific component, which prevents class name collisions.
✅ Uses unique, automatically generated class names under the hood.
🚨 Requires a special import syntax.
Example Case Using CSS Modules:
The Books.module.css file:
.book {
display: flex;
flex-direction: column;
justify-content: flex-start;
align-items: center;
gap: 1rem;
background: linear-gradient(#1d3557, #324766);
padding: 1.5rem;
border-radius: 6px;
box-shadow: 0 2px 10px #455874;
width: 33%;
transition: all 0.2s
}
.book:hover {
transform: translateY(-2px);
transition: transform 0.2s;
box-shadow: 0 2px 20px #324766;
}
.book h2 {
margin: 0;
font-size: 1rem;
text-transform: uppercase;
}
.book p {
margin: 0;
text-align: center;
font-size: 0.95rem;
}The Books.js file:
import React from 'react';
import styles from './Books.module.css'; // Importing CSS Module
function Books(props) {
return props.items.map((item) => (
<li className={styles.book} key={Math.random().toString()}>
<h2>{item.title}</h2>
<p>{item.description}</p>
</li>
));
}
export default Books;- 💡 In CSS Modules, when you import a
.module.cssfile, the styles inside it are automatically converted into a JavaScript object where:- Keys are the class names you defined in the CSS file.
- Values are unique, auto-generated class names to prevent conflicts.
- Using CSS module syntax, the class name is defined between two curly braces (
{}), accessing the.bookclass of thestylesobject (className={styles.book}).
Tip
For more information about CSS Modules, check out the documentation published by the Create React App team.
Note
All examples in this section can be found in 📁 react-fragments
In React, a Fragment is a lightweight component that allows you to group multiple elements without adding extra nodes to the DOM.
This is useful when you need to return multiple elements from a component but don’t want to introduce unnecessary <div> wrappers.
✅ Helps keep the DOM cleaner and avoids unnecessary elements.
✅ Reduces DOM depth and improves rendering efficiency.
✅ Helps when rendering lists where an extra wrapper could interfere with styling.
import React from "react";
function ExplicitEx() {
return (
<React.Fragment>
<h1>Hello</h1>
<p>This is an explicit React Fragment example.</p>
</React.Fragment>
);
}
export default ExplicitEx;
// Can also import "Fragment" from React, and use as: //
// import React from "react";
import { Fragment } from "react";
function ExplicitEx() {
return (
// <React.Fragment>
// <h1>Hello</h1>
// <p>This is an explicit React Fragment example.</p>
// </React.Fragment>
<Fragment>
<h1>Hello</h1>
<p>This is an explicit React Fragment example.</p>
</Fragment>
);
}
export default ExplicitEx;- Groups
<h1>and<p>together without introducing an extra<div>in the DOM.
function ShorthandEx() {
return (
<>
<h1>Hello</h1>
<p>This is an example of using the shorthand syntax for React Fragments.</p>
</>
);
}
export default ShorthandEx;- Shorthand offers simplicity, but does not support attributes.
React Hooks are functions introduced in React 16.8 that allow you to use React's state and lifecycle features in functional components, which were previously only available in class components.
Hooks simplify component logic, making it easier to reuse stateful logic without the need for complex patterns like higher-order components or render props.
React Hooks must follow these rules:
- They must be called at the top level: React hooks should not be called inside loops, conditions, or nested functions.
- They must be called only in React functions: Use hooks only in functional components or custom hooks, not regular JavaScript functions.
React provides several built-in hooks for development, grouped by purpose:
useState: For managing state in functional components.
const [state, setState] = useState(initialState);useEffect: For managing side effects like data fetching or DOM updates.
useEffect(() => {
// Side effect logic here
return () => {
// Cleanup function (optional)
};
}, [dependencies]);useContext: For consuming context without needingContext.Consumer.
const value = useContext(MyContext);useReducer: For managing complex state logic, similar toreduxreducers.
const [state, dispatch] = useReducer(reducer, initialArg);useCallback: For memoizing functions to prevent unnecessary re-creation.
const memoizedCallback = useCallback(() => {
// Function logic
}, [dependencies]);useMemo: For memoizing values to avoid expensive recalculations.
const memoizedValue = useMemo(() => computeExpensiveValue(a, b), [a, b]);useRef: Persist values across renders or directly manipulate DOM elements.
const ref = useRef(initialValue);useImperativeHandle: Customize what is exposed when usingrefin parent components.
useImperativeHandle(ref, () => ({
customMethod() {
// Logic
},
}));-
useLayoutEffect: Similar touseEffect, but runs synchronously after all DOM mutations. -
useDebugValue: For debugging custom hooks.
useDebugValue(value);Tip
Check out the React documentation for a complete list of built-in hooks.
- Custom hooks are user-defined hooks created by combining built-in hooks. They encapsulate reusable logic into a function prefixed with
use.
function useFetch(url) {
const [data, setData] = useState(null);
useEffect(() => {
fetch(url)
.then((res) => res.json())
.then((data) => setData(data));
}, [url]);
return data;
}First look at using the built-in React hook
useStatefor state management.
Note
All examples in this section can be found in 📁 state-management
Overview:
The useState hook in React is used to manage and track state in functional components.
This hook provides a way to store values that can change over time and trigger re-renders when those values change.
Syntax:
const [state, setState] = useState(initialValue);state: The current value of the state.setState: A function to update the state value.initialValue: The initial value of the state.
The StateManagementEx.js File:
import { useState } from 'react';
function StateManagementEx() {
const [count, setCount] = useState(0);
function addHandler() {
setCount(count + 1);
}
function subtractHandler() {
setCount(count - 1);
}
return (
<div>
<h2>Counter Example</h2>
<p>Current Count: {count}</p>
<button onClick={addHandler}>Add 1</button>
<button onClick={subtractHandler}>Subtract 1</button>
</div>
)
}
export default StateManagementEx;useState(0)initializes count variable set to0.- The
setCountfunction is used to update thecountstate and triggers a re-render to reflect the updated value. addHandleris passed to theonClickevent handler and increases the count by 1 when the "Add 1" button is clicked.subtractHandleris passed to theonClickevent handler and decreases the count by 1 when the "Subtract 1" button is clicked.- The
onClickevent handler allows execution of a function when a user clicks on the element.
- The
The App.js File:
import StateManagementEx from "./components/StateManagementEx";
function App() {
return (
<div>
<h1>State Management</h1>
<StateManagementEx />
</div>
);
}
export default App;- Renders the
StateManagementExcomponent.
Tip
Check out the complete React documentation on the built-in useState hook.
A look at managing side effects with the
useEffecthook.
Note
All examples in this section can be found in 📁 react-side-effects
Overview:
useEffect is a built-in React Hook that allows you to perform side effects in functional components.
It runs after the component renders and can be used for tasks such as:
- Fetching data from an API
- Subscribing to events
- Updating the DOM
- Managing timers
Syntax:
useEffect(() => {
// Side effect logic here
return () => {
// Cleanup function (optional)
};
}, [dependencies]);useEffect takes two arguments:
() => {}: The first argument is a function that runs the effect.[dependencies]: The second argument is an array of dependencies that controls when the effect runs. This can be:[](empty array) - Runs only once after the first render.- No dependency array - Runs after every render.
[someValue]→ Runs whensomeValuechanges.
In React, you often here the terms mounts or unmounts with relation to components. These refer to the lifecycle of a component - when it is added (mount) to or removed (unmount) from the DOM (Document Object Model).
A Closer Look at "Mounting":
When a component mounts, it means:
- The component is being created and inserted into the DOM.
- React renders the component for the first time.
- The
useEffecthook, with an empty dependency array, runs once.
Examples of component mounting include:
- A component that is added to the UI.
- A component conditionally rendered based on state.
- A user navigates to a route where the component appears.
A Closer Look at "Unmounting":
When a component unmounts, it means:
- The component is removed from the DOM.
- Any side effects (event listeners, timers, etc.) should be cleaned up to prevent memory leaks.
- The cleanup function in
useEffectruns before unmounting.
Examples of component unmounting include:
- The user navigates away from a route containing the component.
- The component is conditionally removed.
- A parent component re-renders, causing the child component to be removed.
Example Case of "Mounting" and "Unmounting":
useEffect(() => {
console.log('The "Mount" component has been mounted!');
return () => {
console.log('The "Mount" component has been unmounted!');
};
}, []); // Empty dependency array -> Runs once on mountThe Counter.js File:
import React, { useState, useEffect } from "react";
function Counter() {
const [count, setCount] = useState(0);
// Effect 1: Start a time when the component mounts
useEffect(() => {
const interval = setInterval(() => {
setCount(prev => prev + 1);
}, 1000);
// Cleanup function to stop the interval when component unmounts
return () => {
clearInterval(interval);
};
}, []); // Runs only once when the component mounts
// Effect 2: Update the document title whenever count changes
useEffect(() => {
document.title = `Count: ${count}`;
}, [count]); // Runs only when count changes
return (
<div>
<h2>Counter: {count}</h2>
<button onClick={() => setCount(0)}>Reset</button>
</div>
);
}
export default Counter;The App.js File:
import React, { useEffect } from "react";
import Counter from "./components/Counter";
function App() {
// Effect 3: Clear any initial console logs when the component mounts
useEffect(() => {
console.clear();
}, []);
return (
<div>
<h1>React Side Effects - Timer Example</h1>
<Counter />
</div>
);
}
export default App;Tip
Check out the complete React documentation on the built-in useEffect hook.
React project demonstrating the use of
useMemoandReact.memo, as well asuseCallbackfor performance optimization.
- Default Rendering Behavior
- Overview of Optimizations
- Key Differences
- Understanding Memoization
- Understanding Shallow Comparison
- Basic Syntax of useMemo
- Basic Syntax of useCallback
- Basic Syntax of React.memo
- Changes to Default Rendering Behavior
- Project Structure
Note
All examples in this section can be found in 📁 performance-optimization
By default, React will re-render a component when:
- Its state changes → When you call
setState, the component and its children re-render. - Its props change → If a parent component passes new props, the child component re-renders.
- Its parent re-renders → If a parent component re-renders (even without changing props), React re-renders its children.
This default re-rendering behavior ensures that the UI stays in sync with the application state, but this often leads to unnecessary re-renders that negatively impact performance.
That is where useMemo, useCallback, and React.memo come into place. These optimizations, provided by React, help reduce unnecessary re-renders and improve application performance.
The useMemo React Hook is used to optimize performance by memoizing (also known as caching) the result of a function or computation, so that it is only recalculated when its dependencies change. This prevents expensive computations from running unnecessarily during every render.
Tip
Check out the complete React documentation on the built-in useMemo hook.
In React, React.memo is a higher-order component (HOC) provided by React, specifically designed to automatically memoize functional components. When a component is wrapped with React.memo, it will re-render only if its props have changed.
useCallback is a React Hook used to memoize callback functions. It ensures that a function reference remains the same across renders unless its dependencies change.
This optimization is useful when passing callbacks to child components to prevent re-creations of functions during component re-renders.
If you pass a new function reference (even with the same logic) as a prop, React.memo will trigger a re-render. useCallback ensures that the function reference stays the same across renders, working effectively with React.memo.
Tip
Check out the complete React documentation on the built-in useCallback hook.
| Feature | React.memo |
useMemo |
useCallback |
|---|---|---|---|
| Functionality | Prevents a component from re-rendering based on its props. | Caches the result of a function call based on its dependencies. | Caches a function definition so it does not get re-created on every render. |
| Usage | Used to wrap a functional component. | Called inside a functional component to memoize a specific calculation. | Wraps a function inside a functional component. |
| Comparison | Performs a shallow comparison of props by default to determine if a re-render is needed. | Explicitly defines dependencies in an array to control when the calculation is re-run. | Explicitly defines dependencies in an array to determine when the function should be re-created. |
React.memo focuses on optimizing component rendering, while useMemo optimizes specific calculations within a component.
Use Case for Each:
- Use
React.memowhen you have a component that is rendered frequently and its rendering logic is relatively simple but depends heavily on its props. - Use
useMemowhen you have a computationally expensive calculation within a component that needs to be cached and only re-calculated when its dependencies change. - Use
useCallback:- When functions are passed as props, preventing unnecessary child re-renders.
- When passing functions as props to child components wrapped with
React.memo. - When functions are used as dependencies in
useEffectoruseMemoto avoid triggering unintended re-runs.
Caching is a technique that allows us to store a copy of a given resource and serve it back when it is requested.
Memoization is a technique used to optimize the performance of functions by caching the results of expensive function calls and reusing them when the same inputs occur again.
In React applications, memoization helps avoid redundant rendering of components, ultimately leading to a smoother user experience.
Shallow comparison refers to a comparison of references only, not the actual content of the objects. If two variables reference the same object in memory, the shallow comparison will consider them equal. It does not go into nested objects or arrays to check for equality.
const array1 = [1, 2, 3];
const array2 = [1, 2, 3];
const array3 = array1; // Points to the same memory reference as array1
console.log(array1 === array2); // false (different references)
console.log(array1 === array3); // true (same reference)const cachedValue = useMemo(calculateValue, dependencies)calculateValue: The function calculating the value that you want to cache.- React will call this function during the initial render.
- On next renders, React will return the same value if the
dependencieshave not changed.
dependencies:- List of all reactive values referenced inside of the calculateValue code.
- This include props, state, and all the variables and functions declared directly inside your component body.
const memoizedCallback = useCallback(
() => {
// Callback Function (Your callback logic here)
},
[dependencies] // Dependency Array (function recreation if these change)
);- Callback Function - The function you want to memoize.
- Dependency Array - Determines when the memoized function should be recreated.
- A memoized version of the function that only changes if the dependencies change will be returned.
There are multiple ways to use React.memo, here are a few examples:
Example 1:
The React.memo function is used to wrap the component and then export:
import React from 'react';
const ComponentOne = (props) => {
/* component code */
};
export default React.memo(ComponentOne);Example 2:
The memo() function is used to wrap a new variable and then store the memoized component to be exported:
import { memo } from "react";
const ComponentTwo = (props) => {
/* render using props */
};
export const MemoComponent = memo(ComponentTwo);Example 3:
The memo() function is used to wrap the entire component:
import { memo } from "react";
const ComponentThree = memo((props) => {
/* component code */
});
export default ComponentThree;| Feature | Default Behavior | React.memo |
useMemo |
useCallback |
|---|---|---|---|---|
| State Change | Component always re-renders | No effect | No effect | No effect |
| Props Are the Same | Component re-renders | ✅ Prevents re-render | No effect | No effect |
| Parent Re-renders | Child re-renders | ✅ Prevents re-render | No effect | No effect |
| Expensive Computations | Always recalculates | No effect | ✅ Prevents recalculation | No effect |
| Functions as Props | New function created on every render | No effect | No effect | ✅ Prevents re-creation |
performance-optimization/
├── public/
├── index.html
├── favicon.ico
├── manifest.json
└── robots.txt
├── src/
├── components/
| ├── Demo/
| | ├── DemoList.js
| | ├── DemoList.module.css
| ├── UI/
| | ├── Button/
| | | ├── Button.js
| | | ├── Button.module.css
├── App.css
├── App.js
├── index.css
├── index.js
├── .gitignore
├── package.json
├── readme.md
- Overview of HTTP Requests in React
- Understanding Asynchronous Requests in JavaScript
- Making a Request to The Star Wars API
Note
All examples in this section can be found in 📁 making-http-requests
In React applications, HTTP requests are commonly made by using JavaScript's fetch() API or third-party libraries.
These requests are usually performed in lifecycle methods, such as useEffect or useCallback to fetch data from an external API when a component mounts or when triggered by user actions.
In JavaScript, asynchronous operations allow code execution without blocking the main thread, enabling tasks like fetching data, handling user interactions, or waiting for a timer without stopping the execution of other code.
JavaScript is single-threaded, meaning it can only execute one operation at a time. Without asynchronous programming, JavaScript would freeze whenever a long-running task is executed.
Asynchronous operations include callbacks, promises, and async/await mechanisms.
The async and await keywords in JavaScript are used to work with these operations, particularly with Promises. They allow us to write asynchronous code that looks and behaves more like synchronous code, making it easier to read and manage.
- Callbacks (Old Approach - Rarely Used and Not Recommended Anymore)
- Before Promises, callbacks were the primary way to handle asynchronous operations.
function fetchData(callback) {
setTimeout(() => {
callback("Received");
}, 2000);
}
fetchData((result) => {
console.log(result);
});- Biggest issue that came with callbacks was Callback Hell where nesting multiple callbacks led to unreadable code.
- Promises (More Modern Approach)
- A Promise represents a value that will be available in the future. It has three states: pending, fulfilled, and rejected.
// Fetching a JSON file
function fetchData() {
fetch('./movies.json').then((response) => {
return response.json();
}).then((data) => {
console.log(data);
});
}- Promises resolved the issue of callback hell.
- Async/Await (Modern Syntax for Promises)
- The
asyncandawaitkeywords simplify working with Promises.
async function getUsers() {
const res = await fetch('https://jsonplaceholder.typicode.com/users');
const data = await res.json();
console.log(data);
}
async function fetchPost() {
try {
const response = await fetch("https://jsonplaceholder.typicode.com/posts");
const data = await response.json();
console.log(data);
} catch (error) {
console.error("Error:", error);
}
}- Using async/await is more readable then
.then()chaining. - Provides a synchronous-like structure for easier debugging and better error handling.
| Feature | Callbacks | Promises | Async/Await |
|---|---|---|---|
| Readability | Poor (callback hell) | Better (.then() chaining) |
Best (synchronous-like) |
| Error Handling | Difficult | Better (.catch()) |
Best (try...catch) |
| Nesting Issues | Yes | No | No |
| Flexibility | Low | Medium | High |
Note
All Star Wars data at https://swapi.dev/
Importing Component Dependencies:
import React, { useState, useEffect, useCallback } from 'react';
import MoviesList from './components/MoviesList';
import './App.css';Defining Component State:
const [movies, setMovies] = useState([]);
const [isLoading, setIsLoading] = useState(false);
const [error, setError] = useState(null);movieswill store the fetched movie data - initially set to an empty array ([]).isLoadingwill track the status of data being fetched - initially set tofalse.errorwill store any errors that occur during fetching - initially set tonull.
Defining the Movie Fetch Handler:
const fetchMoviesHandler = useCallback(async () => {
setIsLoading(true);
setError(null);
try {
const response = await fetch('https://swapi.dev/api/films/');
if (!response.ok) {
throw new Error(response.status + ' : Something went wrong...');
}
const data = await response.json();
const transformedMovies = data.results.map((movieData) => {
return {
id: movieData.episode_id,
title: movieData.title,
openingText: movieData.opening_crawl,
releaseDate: movieData.release_date,
};
});
setMovies(transformedMovies);
} catch (error) {
setError(error.message);
}
setIsLoading(false);
}, []);Looking at useCallback
const fetchMoviesHandler = useCallback(async () => { ... }, []);- The dependency array in this function is empty (
[]), which means the function is created only once when the component first renders.
Updating State Variables
setIsLoading(true);
setError(null);setIsLoading(true): Data starts loading -isLoadingstate is set totrue.setError(null): This resets the error state to its initial state, if any previous errors occurred.
The try...catch block
try {
const response = await fetch('https://swapi.dev/api/films/');
...
}- Fetches data from the external Star Wars API.
awaitensures the function waits for the API response before continuing execution.- What is returned from the API call is stored in the
responsevariable.
if (!response.ok) {
throw new Error(response.status + ' : Something went wrong...');
}- Checks if the response returned is of the status code 4xx or 5xx, such as 404 Not Found or 500 Internal Server Error.
- If the status is not OK, then a new error is thrown with a message including the HTTP status code.
const data = await response.json();- Parses the response by converting from JSON format into a JavaScript object.
awaitensures it waits until the JSON is completely parsed.
const transformedMovies = data.results.map((movieData) => {
return {
id: movieData.episode_id,
title: movieData.title,
openingText: movieData.opening_crawl,
releaseDate: movieData.release_date,
};
});
setMovies(transformedMovies);- The Star Wars API returns an array of movie objects inside
data.results. .map()is used to loop through each movie and extracts only the needed properties.setMovies(transformedMovies)updates the state, triggering a re-render to display the new movie list.
catch (error) {
setError(error.message);
}- If an error occurs anywhere inside the
tryblock, execution jumps to thecatchblock, where the error message is stored in React state (setError(error.message)).
Final Cleanup
setIsLoading(false);- Sets the loading state back to false, ensuring it is done whether the fetch was successful or an error occurred.
Fetching Data on Component Mount:
useEffect(() => {
fetchMoviesHandler();
}, [fetchMoviesHandler]);- Ensures that
fetchMoviesHandlerruns automatically when the component first mounts. - Since
fetchMoviesHandleris wrapped withuseCallback, React ensures it does not cause unnecessary re-renders.
UI State Handling:
let content = <p>No movies found.</p>;
if (movies.length > 0) {
content = <MoviesList movies={movies} />;
}
if (error) {
content = <p>{error}</p>;
}
if (isLoading) {
content = <p>Loading...</p>;
}- Renders a different UI based on status of state:
- Shows "No movies found." if no movies are available.
- Displays the
MoviesListcomponent if movies exist (passing themoviesas prop). - Shows an error message if fetching fails.
- Displays "Loading..." while the request is in progress.
Rendering the UI:
return (
<React.Fragment>
<section>
<button onClick={fetchMoviesHandler}>Find Movies</button>
</section>
<section>{content}</section>
</React.Fragment>
);- A button manually triggers
fetchMoviesHandler. - Dynamically displays the updates of
contentbased onmovies,isLoading, anderror.
Exporting the Component:
export default App;- Makes
Appavailable for use inindex.js(or any other part of the app).
| Project | Description | Link |
|---|---|---|
| Introduction Project | Basic introduction to React concepts | 🔗📁 |
| Key React Concepts | UI for displaying key React concepts | 🔗📁 |
| Base React App | Template structure for React projects | 🔗📁 |
| React Fragments | Using React fragments for cleaner JSX | 🔗📁 |
| Function vs Class Components | Comparing component styles | 🔗📁 |
| Class-Based Components | Working with class components and lifecycle | 🔗📁 |
| Project | Description | Link |
|---|---|---|
| Using CSS Modules | Scoped styling with CSS Modules | 🔗📁 |
| Hoverboard Effect | Fun interactive hoverboard effect | 🔗📁 |
| Login Page UI | Login page with input validation | 🔗📁 |
| Animating React Apps | Adding animations to React components | 🔗📁 |
| Project | Description | Link |
|---|---|---|
| State Management | Managing component and application state | 🔗📁 |
| Course Goal | Adding course goals to a list | 🔗📁 |
| Add User | Adding users to a list | 🔗📁 |
| Investment Calculator | Calculating and displaying investments | 🔗📁 |
| Expense Tracker | App for keeping track of expenses | 🔗📁 |
| Forms and User Input | Handling forms and validation | 🔗📁 |
| Project | Description | Link |
|---|---|---|
| React Side Effects | Using useEffect for side effects | 🔗📁 |
| Custom React Hooks | Building reusable custom hooks | 🔗📁 |
| Custom React Hooks Pt. 2 | Advanced custom hook patterns | 🔗📁 |
| Project | Description | Link |
|---|---|---|
| Sending HTTP Requests | Fetching data from APIs | 🔗📁 |
| HTTP Requests Pt. 2 | Advanced HTTP patterns | 🔗📁 |
| Pokemon Cards | Fetching and displaying Pokemon data | 🔗📁 |
| Book Finder | Searching books via Open Library API | 🔗📁 |
| Book Finder with Router | Book search with React Router | 🔗📁 |
| Project | Description | Link |
|---|---|---|
| React Router | Introduction to React Router | 🔗📁 |
| Advanced React Router | Complex routing patterns | 🔗📁 |
| Adding Authentication | Auth with protected routes | 🔗📁 |
| Project | Description | Link |
|---|---|---|
| Redux Basics | Introduction to Redux | 🔗📁 |
| Redux React Project | Integrating Redux with React | 🔗📁 |
| Advanced Redux | Advanced Redux patterns and async | 🔗📁 |
| Project | Description | Link |
|---|---|---|
| Food Order App | Online food ordering cart | 🔗📁 |
| Adding HTTP to Food Order | Food order app with backend | 🔗📁 |
| Project | Description | Link |
|---|---|---|
| Performance Optimization | React performance techniques | 🔗📁 |
| Optimization Techniques | Advanced optimization patterns | 🔗📁 |
| Testing with Jest | Unit and integration testing | 🔗📁 |
| Project | Description | Link |
|---|---|---|
| Deploying React Apps | Deployment strategies | 🔗📁 |
| Next.js Dummy News | Server-side rendering with Next.js | 🔗📁 |
| Next.js Meetup App | Full Next.js application | 🔗📁 |