≡ Menu

In the world of web development, data is king.

But data is rarely sitting right inside your code—it lives on external servers, waiting to be “fetched.”

Whether you’re building a stock market tracker, a social media feed, or a sports scoreboard, the Fetch API is the bridge between your user interface and the rest of the world.

It is the modern standard for making network requests in JavaScript, replacing the old, clunky methods of the past with a clean, Promise-based syntax.

But theory only takes you so far. To truly master Fetch, you need to build something real.

In this tutorial, we’re going to build a Modern Weather Dashboard.

We’ll learn how to:

  • Connect to a real-world API (OpenWeatherMap).

  • Handle multiple asynchronous calls using async/await.

  • Manage errors gracefully so your app doesn’t crash.

  • Transform raw JSON data into a beautiful, glassmorphism-inspired UI.

Ready to turn some code into a living, breathing application? Let’s dive in.

Prerequisites

  1. An API Key: Sign up for a free account at OpenWeatherMap and generate an API key.

  2. Basic HTML/CSS/JS knowledge.

  3. A code editor (like VS Code).


Step 1: The HTML Blueprint

We need a clean UI. We’ll use a search input, a main card for current weather, and a grid for the 5-day forecast.

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>Weather Dashboard</title>
    <link rel="stylesheet" href="style.css">
</head>
<body>
    <div class="container">
        <header>
            <h1>WeatherPro</h1>
            <div class="search-area">
                <input type="text" id="cityInput" placeholder="Search city...">
                <button id="searchBtn">Get Weather</button>
            </div>
        </header>

        <main id="weatherContent" class="hidden">
            <section class="current-card">
                <div class="main-info">
                    <h2 id="cityName">---</h2>
                    <img id="mainIcon" src="" alt="">
                    <h1 id="mainTemp">--°C</h1>
                </div>
                <div class="details">
                    <p>Humidity: <span id="humidity">--</span>%</p>
                    <p>Wind: <span id="wind">--</span> km/h</p>
                </div>
            </section>

            <section class="forecast-section">
                <h3>5-Day Forecast</h3>
                <div id="forecastGrid" class="grid"></div>
            </section>
        </main>
    </div>
    <script src="script.js"></script>
</body>
</html>

Step 2: Styling with CSS

Let’s give it a modern “Glassmorphism” look—popular for weather apps in 2026.

body {
    font-family: 'Segoe UI', sans-serif;
    background: linear-gradient(135deg, #1e3c72 0%, #2a5298 100%);
    color: white;
    min-height: 100vh;
    display: flex;
    justify-content: center;
}

.container { width: 90%; max-width: 800px; padding: 20px; }

.search-area { margin-bottom: 30px; display: flex; gap: 10px; }

input { 
    flex: 1; padding: 10px; border-radius: 8px; border: none; 
}

button { 
    padding: 10px 20px; border-radius: 8px; border: none; 
    background: #ff7e5f; color: white; cursor: pointer;
}

.current-card {
    background: rgba(255, 255, 255, 0.1);
    backdrop-filter: blur(10px);
    border-radius: 15px;
    padding: 30px;
    display: flex;
    justify-content: space-around;
    align-items: center;
}

.grid {
    display: grid;
    grid-template-columns: repeat(auto-fit, minmax(120px, 1fr));
    gap: 15px;
    margin-top: 20px;
}

.forecast-card {
    background: rgba(255, 255, 255, 0.05);
    padding: 15px;
    border-radius: 10px;
    text-align: center;
}

.hidden { display: none; }

Step 3: The Fetch Logic (script.js)

This is the “brain” of the app. We will use two different endpoints: one for current weather and one for the 5-day forecast.

const API_KEY = 'YOUR_API_KEY_HERE';
const searchBtn = document.getElementById('searchBtn');

searchBtn.addEventListener('click', async () => {
    const city = document.getElementById('cityInput').value;
    if (!city) return;

    try {
        // Fetching Current Weather
        const weatherRes = await fetch(
            `https://api.openweathermap.org/data/2.5/weather?q=${city}&units=metric&appid=${API_KEY}`
        );

        if (!weatherRes.ok) throw new Error('City not found');
        const weatherData = await weatherRes.json();

        // Fetching 5-Day Forecast
        const forecastRes = await fetch(
            `https://api.openweathermap.org/data/2.5/forecast?q=${city}&units=metric&appid=${API_KEY}`
        );
        const forecastData = await forecastRes.json();

        updateUI(weatherData, forecastData);
    } catch (err) {
        alert(err.message);
    }
});

function updateUI(current, forecast) {
    document.getElementById('weatherContent').classList.remove('hidden');
    
    // Update Current Weather
    document.getElementById('cityName').textContent = current.name;
    document.getElementById('mainTemp').textContent = `${Math.round(current.main.temp)}°C`;
    document.getElementById('humidity').textContent = current.main.humidity;
    document.getElementById('wind').textContent = current.wind.speed;
    document.getElementById('mainIcon').src = 
        `https://openweathermap.org/img/wn/${current.weather[0].icon}@2x.png`;

    // Update Forecast
    const grid = document.getElementById('forecastGrid');
    grid.innerHTML = ''; // Clear previous data

    // The API gives data in 3-hour blocks. We want 1 block per day (every 8th item).
    const dailyData = forecast.list.filter((_, index) => index % 8 === 0);

    dailyData.forEach(day => {
        const date = new Date(day.dt_txt).toLocaleDateString('en-US', { weekday: 'short' });
        grid.innerHTML += `
            <div class="forecast-card">
                <p><strong>${date}</strong></p>
                <img src="https://openweathermap.org/img/wn/${day.weather[0].icon}.png">
                <p>${Math.round(day.main.temp)}°C</p>
            </div>
        `;
    });
}

Step 4: Pro-Tips for Modern Apps

  1. Loading States: Before calling fetch(), change the button text to “Loading…” and disable it. Re-enable it once the data arrives.

  2. Environment Variables: In a real production app, never hardcode your API_KEY. Use a .env file or a backend proxy to hide it.

  3. Unit Switching: You can easily add a toggle that changes the URL parameter from units=metric to units=imperial to support Fahrenheit.


Final Thoughts

Using Fetch with async/await turns complex network logic into something that reads like a story.

You request data, wait for the response, check if it’s “OK,” and then display it.

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 }

In the world of React, every time a parent component’s state changes, React’s default behavior is to re-render every single one of its children.

In small apps, this is fine. In large apps, this leads to “laggy” interfaces.

Today, we’ll look at how to stop unnecessary renders using your provided code as a master blueprint.


The Problem: The “Default” Render Behavior

Imagine clicking a “Counter” button. The number goes up, but your huge list of 1,000 items also refreshes—even though the list didn’t change!

This happens because React recreates everything inside the Parent function on every render, including new instances of your functions.


Step 1: React.memo (The Shield)

The first line of defense is memo. It tells React: “Only re-render this child if its props have actually changed.”

const List = memo(({ items, onItemClick }) => {
  console.log("List rendered"); // This will now only log when absolutely necessary
  return (
    <ul>
      {items.map(item => (
        <li key={item} onClick={() => onItemClick(item)}>{item}</li>
      ))}
    </ul>
  );
});

What happens now?

When the count state in the Parent changes, React looks at the List. It checks the items prop and the onItemClick prop.

If they look the same as last time, it skips the work.


Step 2: useCallback (The Anchor)

Even with memo, the List might still re-render.

Why?

Because of Referential Equality.

In JavaScript, function() {} === function() {} is false.

Every time Parent renders, handleItemClick is a “brand new” function in memory.

To memo, a new function means a changed prop.

We fix this with useCallback:

// Inside Parent component
const handleItemClick = useCallback((item) => {
  console.log("Clicked:", item);
}, []); // The empty array ensures this function instance is created ONLY ONCE

useCallback “anchors” the function. It tells React: “Keep this exact same version of the function in memory across all future renders.”


Step 3: The Connection (onItemClick={handleItemClick})

This is where the magic happens. In your JSX, you pass the anchored function to the shielded component:

<List items={items} onItemClick={handleItemClick} />
  1. The User Clicks: When a user clicks “Banana”, the li triggers the anonymous function () => onItemClick(item).

  2. The Bridge: onItemClick is just a reference (a pointer) to handleItemClick.

  3. The Result: The code in the Parent executes. Because the reference never changed, the List stayed perfectly still while the count updated.


When Should You Use This?

Don’t wrap everything! Use this “Power Couple” when:

  • The child component (List) is expensive to render (has lots of elements or complex logic).

  • The child component is wrapped in memo.

  • The function is passed as a dependency to a useEffect inside a child.


Summary Table

Tool Role What it prevents
React.memo Component Wrapper Re-rendering the child if props stay the same.
useCallback Hook Re-creating the function instance on every render.
[] Dependencies Guard Rails Prevents the function from updating unless specific values change.

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 }