Skip to content

sidneyshafer/complete-react-guide

Folders and files

NameName
Last commit message
Last commit date

Latest commit

 

History

246 Commits
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 

Repository files navigation

Complete guide to building applications in React.

Table of Contents


Introduction to React

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.


Back to Top

Tech Stack & Prerequisites

Core Technologies

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

Prerequisites

  • Node.js (v18 or higher recommended)
  • npm (v9 or higher) or yarn
  • Basic knowledge of JavaScript (ES6+)
  • Familiarity with HTML and CSS

Development Tools

  • Code editor (VS Code recommended)
  • Browser with React DevTools extension
  • Git for version control

Quick Start

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-app

Install dependencies and start the development server:

npm install
npm start

The app will open at http://localhost:3000.

Tip

Each project folder contains its own readme.md with specific instructions and documentation.

Creating a New React App

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-app package 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-app with 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.png and logo512.png
      • Logos displaying the specific React symbol (these are usually discarded).
    • favicon.ico and manifest.json
      • Used to provide metadata for the app.
      • The favicon is 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.js file: 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.js component.
      • Used in App.js component with the import statement: import './App.css';.
    • 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.


Back to Top

📌 React App Usage

Usage for setting up, installing, and managing the React app environment and dependencies is outlined in the React application usage documentation.


Back to Top

Base React App

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';

  • ReactDOM is a library that interacts with the DOM to render React components.
  • react-dom/client is a new way (starting from React 18) to manage rendering in React apps, replacing ReactDOM.render.

import './index.css';

  • Imports the global CSS file for the app.

import App from './App';

  • Imports the App component from App.js, which serves as the root component of the application.
  • The App component 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 in public/index.html) and creates a React root using ReactDOM.createRoot.
  • The root serves as the entry point for the React application, allowing React to manage the DOM within this element.
  • In the index.html file, this is the target DOM element where the entire React app will be mounted:
    <div id="root"></div>

root.render(<App />);

  • Renders the App component inside the root element in the DOM.
  • The <App /> syntax is JSX, representing a React component.

The summary, the index.js component:

  1. Sets up the environment.
  2. Renders the top-level App component into the root DOM 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 return statement specifies what the App component 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 App component as the default export of the file.
  • Allows other files to import App (in index.js as import App from './App';) and use it in the application.
  • In a larger app, the App component would usually serve as the container for other components, managing and rendering their content.

In summary, the App.js component:

  1. Defines a simple functional React component.
  2. Renders an HTML structure using JSX.
  3. 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.


Back to Top

React Component Types

A Look at function and class component definitions.

Note

All examples in this section can be found in 📁 function-class-components

Function 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 function keyword.
  • Accepts props for any data from the parent component that uses it (access props.text in this case).
  • The export default statement makes this component available for import in other files of the project.

Class Components

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.props is used to access the props passed to the component from the App component.
  • The render() method is required in class components to return the JSX to be rendered.

Comparison of Components

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.


Back to Top

Introduction Project

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 div with a class of backdrop.
    • className is the attribute used to assign CSS classes to elements in JSX. It is the equivalent of the class attribute in HTML.
  • It takes a prop called onClick, which is a function.
  • When the Backdrop is clicked, it calls the onClick function passed from the parent component.
  • The Backdrop component, 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 div with a class of modal.
  • Contains a paragraph displaying the text prop, and two buttons ("Cancel" and "Confirm"), both of which execute the onClose function 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 Modal and Backdrop components.
  • Imports the React usState hook, which is used to manage and track state in functional components.
  • In this example, usState is used to manage the showModal variable.
  • Renders a card with a title (props.text) and a "Delete" button.
  • Clicking the "Delete" button triggers the showModalHandler, setting showModal to true with:
    • Backdrop displayed - clicking it calls closeModalHandler to hide the modal.
    • Modal displayed, asking the user for confirmation. Clicking either "Cancel" or "Confirm" also calls closeModalHandler.

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 Todo component.
  • Renders the title "React Todo List" and a three Todo components.


Back to Top

CSS Modules for Styling

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 className property is used to assign a class name.
    • This is equivalent to the class property in HTML elements.
    • Using basic CSS files, a string defining the class name is used.

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.css file, 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 .book class of the styles object (className={styles.book}).

Tip

For more information about CSS Modules, check out the documentation published by the Create React App team.


Back to Top

React Fragments

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.

Using the Explicit React.Fragment Syntax

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.

Using the Shorthand Syntax

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.


Back to Top

Overview of React Hooks


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:

  1. They must be called at the top level: React hooks should not be called inside loops, conditions, or nested functions.
  2. 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 needing Context.Consumer.
const value = useContext(MyContext);
  • useReducer: For managing complex state logic, similar to redux reducers.
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 using ref in parent components.
useImperativeHandle(ref, () => ({
  customMethod() {
    // Logic
  },
}));
  • useLayoutEffect: Similar to useEffect, 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;
}


Back to Top

State Management

First look at using the built-in React hook useState for state management.

Note

All examples in this section can be found in 📁 state-management

State Management Overview

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.

Example With useState

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 to 0.
  • The setCount function is used to update the count state and triggers a re-render to reflect the updated value.
  • addHandler is passed to the onClick event handler and increases the count by 1 when the "Add 1" button is clicked.
  • subtractHandler is passed to the onClick event handler and decreases the count by 1 when the "Subtract 1" button is clicked.
    • The onClick event handler allows execution of a function when a user clicks on the element.

The App.js File:

import StateManagementEx from "./components/StateManagementEx";

function App() {
  return (
    <div>
      <h1>State Management</h1>
      <StateManagementEx />
    </div>
  );
}

export default App;
  • Renders the StateManagementEx component.

Tip

Check out the complete React documentation on the built-in useState hook.


Back to Top

React Side Effects

A look at managing side effects with the useEffect hook.

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 when someValue changes.

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 useEffect hook, 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 useEffect runs 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 mount

The 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.


Back to Top

Performance Optimization

React project demonstrating the use of useMemo and React.memo, as well as useCallback for performance optimization.

Note

All examples in this section can be found in 📁 performance-optimization

By default, React will re-render a component when:

  1. Its state changes → When you call setState, the component and its children re-render.
  2. Its props change → If a parent component passes new props, the child component re-renders.
  3. 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.

useMemo

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.

React.memo

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

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.memo when you have a component that is rendered frequently and its rendering logic is relatively simple but depends heavily on its props.
  • Use useMemo when 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 useEffect or useMemo to 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 dependencies have 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


Back to Top

Sending HTTP Requests

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.

  1. 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.

  1. 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.

  1. Async/Await (Modern Syntax for Promises)
  • The async and await keywords 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.

Summary of Asynchronous Operations

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/ ↗️

The App.js File

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);
  • movies will store the fetched movie data - initially set to an empty array ([]).
  • isLoading will track the status of data being fetched - initially set to false.
  • error will store any errors that occur during fetching - initially set to null.

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 - isLoading state is set to true.
  • 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.
  • await ensures the function waits for the API response before continuing execution.
  • What is returned from the API call is stored in the response variable.
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.
  • await ensures 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 try block, execution jumps to the catch block, 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 fetchMoviesHandler runs automatically when the component first mounts.
  • Since fetchMoviesHandler is wrapped with useCallback, 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 MoviesList component if movies exist (passing the movies as 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 content based on movies, isLoading, and error.

Exporting the Component:

export default App;
  • Makes App available for use in index.js (or any other part of the app).


Back to Top

All React Demo Projects

Fundamentals

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 🔗📁

Styling

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 🔗📁

State & Data

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 🔗📁

Hooks

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 🔗📁

HTTP & APIs

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 🔗📁

Routing

Project Description Link
React Router Introduction to React Router 🔗📁
Advanced React Router Complex routing patterns 🔗📁
Adding Authentication Auth with protected routes 🔗📁

State Management (Redux)

Project Description Link
Redux Basics Introduction to Redux 🔗📁
Redux React Project Integrating Redux with React 🔗📁
Advanced Redux Advanced Redux patterns and async 🔗📁

Full Applications

Project Description Link
Food Order App Online food ordering cart 🔗📁
Adding HTTP to Food Order Food order app with backend 🔗📁

Performance & Testing

Project Description Link
Performance Optimization React performance techniques 🔗📁
Optimization Techniques Advanced optimization patterns 🔗📁
Testing with Jest Unit and integration testing 🔗📁

Deployment & Next.js

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 🔗📁


Back to Top

About

Complete guide to building React applications

Topics

Resources

Stars

Watchers

Forks

Releases

No releases published

Packages

 
 
 

Contributors