≡ Menu

The Fetch API is the modern standard for making network requests in the browser, and pairing it with async and await provides the cleanest, most readable way to handle asynchronous operations.

Understanding async and await

 

  • async: This keyword is placed before a function declaration (async function getData() { ... }) to indicate that the function will always return a Promise.

  • await: This keyword can only be used inside an async function. It pauses the execution of the async function until the Promise it precedes is resolved (or rejected), effectively making asynchronous code look and behave like synchronous code.

Step-by-Step GET Request Example

 

Here is a template for fetching JSON data using async/await and the fetch API.

1. Define the async Function

Start by defining your function with the async keyword. It’s best practice to wrap your asynchronous code in a try...catch block to handle potential errors.

async function fetchData(url) {
  try {
    // ... code to fetch and process data
  } catch (error) {
    // ... code to handle errors
  }
}

2. Fetch the Resource

 

Use await before the fetch() call. The fetch() function returns a Promise that resolves to a Response object.

const response = await fetch(url);

3. Check for HTTP Errors

The fetch API’s promise only rejects on network errors (like a dropped connection). It does not reject on HTTP error status codes like 404 or 500.

You must manually check the response’s ok property, which is true for a 200-299 status range

if (!response.ok) {
  throw new Error(`HTTP error! Status: ${response.status}`);
}

4. Extract the JSON Data

 

The Response object has a .json() method which returns a Promise that resolves to the parsed JSON data. Use await again to pause execution until the data is fully parsed.

const data = await response.json();
return data;

Complete GET Example

 

async function fetchPost(id) {
  const url = `https://jsonplaceholder.typicode.com/posts/${id}`; // Example API URL
  try {
    let response = await fetch(url);

    if (!response.ok) {
      throw new Error(`HTTP error! Status: ${response.status}`);
    }

    let data = await response.json();
    console.log("Fetched Data:", data);
    return data;
  } catch (error) {
    console.error("Error fetching data:", error);
  }
}

fetchPost(1);

🛠️ Handling Other Request Methods (POST/PUT/DELETE)

 

To use other HTTP methods like POST, you need to pass a second argument to fetch()—an options object. This object specifies the method, headers, and a body for the request.

POST Example

To send data (e.g., a new post), you must include:

  • method: 'POST'

  • headers: Crucially, Content-Type: 'application/json' tells the server to expect JSON data.

  • body: The data you are sending, converted to a JSON string using JSON.stringify().

async function createPost(postData) {
  const url = 'https://jsonplaceholder.typicode.com/posts';
  try {
    const response = await fetch(url, {
      method: 'POST',
      headers: {
        'Content-Type': 'application/json',
      },
      body: JSON.stringify(postData),
    });

    if (!response.ok) {
      throw new Error(`HTTP error! Status: ${response.status}`);
    }

    const newPost = await response.json();
    console.log("New Post Created:", newPost);
    return newPost;
  } catch (error) {
    console.error("Error creating post:", error);
  }
}

createPost({ title: 'My New Post', body: 'This is the content.', userId: 1 });

Useful links below:

Let me & my team build you a money making website/blog for your business https://bit.ly/tnrwebsite_service

Get Bluehost hosting for as little as $1.99/month (save 75%)…https://bit.ly/3C1fZd2

Best email marketing automation solution on the market! http://www.aweber.com/?373860

Build high converting sales funnels with a few simple clicks of your mouse! https://bit.ly/484YV29

Join my Patreon for one-on-one coaching and help with your coding…https://www.patreon.com/c/TyronneRatcliff

Buy me a coffee ☕️https://buymeacoffee.com/tyronneratcliff

{ 0 comments }

🛒 Building a Simple E-Commerce Cart in React

Welcome to the ultimate guide for building a core feature of any modern web application: a fully functional shopping cart!

In the world of e-commerce, the shopping cart is more than just a list—it’s the critical hub where user interaction meets application state. As React developers, understanding how to manage this dynamic state is fundamental.

This tutorial dives into a clean, component-driven approach to building a shopping cart using React Hooks (useState). You’ll learn essential techniques like:

  • State Immortality: Updating arrays correctly in React.

  • Prop Drilling: Passing functions and data down through components.

  • Component Composition: Structuring your application into reusable pieces (ProductCard, ProductList, and Cart).

By the end of this guide, you won’t just have a working cart; you’ll have mastered the state management principles needed to build any complex feature in a modern React application.

Let’s dive in and start coding!

🏗️ Project Structure and Setup

 

We need four files in total for this improved structure:

src/
├── components/
│   ├── Cart.js
│   ├── ProductList.js
│   └── ProductCard.js  <-- NEW COMPONENT
├── data.js
└── App.js

1. The Data (data.js)

 

Our list of products remains the same:

// data.js
export const products = [
  { id: 1, name: 'Laptop', price: 1200 },
  { id: 2, name: 'Mouse', price: 25 },
  { id: 3, name: 'Keyboard', price: 75 },
  { id: 4, name: 'Monitor', price: 300 },
];

📦 Presentation Components

 

2. Product Card (components/ProductCard.js)

 

This component handles the display of a single product and provides the button to interact with the cart.

// components/ProductCard.js
import React from 'react';

const ProductCard = ({ product, onAddToCart }) => {
  return (
    <div 
      style={{ border: '1px solid #eee', padding: '15px', borderRadius: '5px' }}
    >
      <h3>{product.name}</h3>
      <p>**${product.price.toFixed(2)}**</p>
      {/* The button triggers the onAddToCart function passed down from App.js */}
      <button 
        onClick={() => onAddToCart(product)} 
        style={{ padding: '10px', backgroundColor: 'teal', color: 'white', border: 'none', cursor: 'pointer' }}
      >
        Add to Cart
      </button>
    </div>
  );
};

export default ProductCard;

3. Product List (components/ProductList.js)

 

This component is the container. It receives the list of products and the onAddToCart function as props, and its sole job is to map over the list and render a ProductCard for each item.

// components/ProductList.js
import React from 'react';
import ProductCard from './ProductCard'; // <-- Import the Card

const ProductList = ({ products, onAddToCart }) => {
  return (
    <div style={{ display: 'grid', gridTemplateColumns: 'repeat(2, 1fr)', gap: '20px' }}>
      {products.map(product => (
        <ProductCard 
          key={product.id} 
          product={product} 
          onAddToCart={onAddToCart} 
        />
      ))}
    </div>
  );
};

export default ProductList;

4. Cart Display (components/Cart.js)

This component remains the same, responsible for displaying the items and the total.

// components/Cart.js
import React from 'react';

const Cart = ({ items, total, onRemoveFromCart }) => {
  return (
    <div>
      {/* ... (Cart rendering logic remains the same) ... */}
      {items.length === 0 ? (
        <p>Your cart is empty.</p>
      ) : (
        <>
          <ul style={{ listStyle: 'none', padding: 0 }}>
            {items.map(item => (
              <li 
                key={item.id} 
                style={{ display: 'flex', justifyContent: 'space-between', marginBottom: '10px', borderBottom: '1px dotted #ccc', paddingBottom: '5px' }}
              >
                <span>{item.name} (x{item.quantity})</span>
                <span>
                  **${(item.price * item.quantity).toFixed(2)}**
                  <button 
                    onClick={() => onRemoveFromCart(item.id)}
                    style={{ marginLeft: '10px', backgroundColor: 'red', color: 'white', border: 'none', cursor: 'pointer', padding: '5px 8px' }}
                  >
                    -
                  </button>
                </span>
              </li>
            ))}
          </ul>
          <hr />
          <h3>Total: **${total.toFixed(2)}**</h3>
        </>
      )}
    </div>
  );
};

export default Cart;

️ The Main Application Logic (App.js)

 

This file is the central hub for state management and passing down the necessary props (data and functions) to its children.

// App.js
import React, { useState } from 'react';
import { products } from './data';
import ProductList from './components/ProductList'; // <-- Imported
import Cart from './components/Cart';

function App() {
  const [cartItems, setCartItems] = useState([]);

  // Function to add an item to the cart (Logic remains the same)
  const addToCart = (product) => {
    const existingItem = cartItems.find(item => item.id === product.id);

    if (existingItem) {
      setCartItems(
        cartItems.map(item =>
          item.id === product.id
            ? { ...item, quantity: item.quantity + 1 }
            : item
        )
      );
    } else {
      setCartItems([...cartItems, { ...product, quantity: 1 }]);
    }
  };

  // Function to remove an item or decrease quantity (Logic remains the same)
  const removeFromCart = (productId) => {
    setCartItems(
      cartItems.reduce((acc, item) => {
        if (item.id === productId) {
          if (item.quantity > 1) {
            acc.push({ ...item, quantity: item.quantity - 1 });
          }
        } else {
          acc.push(item);
        }
        return acc;
      }, [])
    );
  };

  // Calculate the total cost
  const cartTotal = cartItems.reduce(
    (total, item) => total + item.price * item.quantity,
    0
  );

  return (
    <div className="App" style={{ padding: '20px' }}>
      <h1>️ Simple E-Commerce App</h1>
      <div style={{ display: 'flex', gap: '40px' }}>
        
        {/* Product List Section - Uses the ProductList container */}
        <section style={{ flex: 2 }}>
          <h2>Products</h2>
          <ProductList 
            products={products} 
            onAddToCart={addToCart} // <-- Passing the function down
          />
        </section>

        {/* Cart Section */}
        <section style={{ flex: 1, borderLeft: '1px solid #ccc', paddingLeft: '20px' }}>
          <h2>Your Cart</h2>
          <Cart
            items={cartItems}
            total={cartTotal}
            onRemoveFromCart={removeFromCart}
          />
        </section>
      </div>
    </div>
  );
}

export default App;

Benefits of Component Separation

 

By splitting the product display into two components, we achieve better React practices:

  • ProductList: Responsible for listing (the structure and mapping).

  • ProductCard: Responsible for presenting a single item’s details and handling its specific action (the button).

This makes it easy to change the appearance of a product card without touching the listing logic, and vice versa.

Useful links below:

Let me & my team build you a money making website/blog for your business https://bit.ly/tnrwebsite_service

Get Bluehost hosting for as little as $1.99/month (save 75%)…https://bit.ly/3C1fZd2

Best email marketing automation solution on the market! http://www.aweber.com/?373860

Build high converting sales funnels with a few simple clicks of your mouse! https://bit.ly/484YV29

Join my Patreon for one-on-one coaching and help with your coding…https://www.patreon.com/c/TyronneRatcliff

Buy me a coffee ☕️https://buymeacoffee.com/tyronneratcliff

{ 0 comments }