Build a Simple Next.js Interactive Weather App

Written by

in

In today’s interconnected world, weather information is more accessible and crucial than ever. From planning your day to understanding global climate patterns, having a reliable source of weather data at your fingertips is invaluable. This is where a weather application comes in. But what if you could build your own, tailored to your needs and preferences, using the power of Next.js?

Why Build a Weather App with Next.js?

Next.js offers a fantastic development experience for building modern web applications. Its features like server-side rendering (SSR), static site generation (SSG), and API routes make it an ideal choice for a weather app. Here’s why:

  • Performance: Next.js optimizes your application for speed, ensuring a smooth user experience.
  • SEO: SSR and SSG improve your app’s search engine optimization (SEO), making it easier for users to find.
  • API Routes: Easily create backend API endpoints to fetch weather data from external services.
  • Developer Experience: Features like hot module replacement and built-in CSS support streamline the development process.

Project Overview: The Interactive Weather App

In this tutorial, we will build a simple, yet functional, weather application using Next.js. Our app will:

  • Allow users to input a city name.
  • Fetch weather data for the specified city from a weather API.
  • Display current weather conditions, including temperature, description, and other relevant information.
  • Provide a clean and intuitive user interface.

This project is perfect for beginners and intermediate developers looking to deepen their understanding of Next.js and web development concepts. Let’s get started!

Prerequisites

Before we begin, make sure you have the following installed:

  • Node.js and npm: You’ll need Node.js and npm (Node Package Manager) installed on your system. You can download them from nodejs.org.
  • A Code Editor: Choose your favorite code editor. Visual Studio Code, Sublime Text, or Atom are all excellent choices.
  • Basic Knowledge of HTML, CSS, and JavaScript: Familiarity with these languages will be helpful.

Step-by-Step Instructions

1. Setting Up Your Next.js Project

Let’s start by creating a new Next.js project. Open your terminal and run the following command:

npx create-next-app weather-app
cd weather-app

This command creates a new Next.js project named “weather-app” and navigates you into the project directory.

2. Installing Dependencies

Next, we need to install the necessary dependencies. We’ll use the axios library to make API requests to fetch weather data. Run the following command in your terminal:

npm install axios

3. API Key and Weather API

To fetch weather data, we’ll use a weather API. There are many free and paid weather APIs available. For this tutorial, we’ll use the OpenWeatherMap API, which offers a free tier. You’ll need to:

  • Sign up for an API key: Go to openweathermap.org and create a free account to obtain your API key.
  • Store your API key securely: Never commit your API key directly into your codebase. We’ll use environment variables to store it. Create a .env.local file in the root of your project and add the following line, replacing YOUR_API_KEY with your actual API key:
    OPENWEATHERMAP_API_KEY=YOUR_API_KEY
    

4. Creating the Weather Fetching Logic (API Route)

Next.js allows us to create API routes, which are serverless functions that handle backend logic. Let’s create an API route to fetch weather data. Create a file named pages/api/weather.js and add the following code:

// pages/api/weather.js
import axios from 'axios';

export default async function handler(req, res) {
  const { city } = req.query;
  const apiKey = process.env.OPENWEATHERMAP_API_KEY;

  if (!city) {
    return res.status(400).json({ error: 'City parameter is required' });
  }

  try {
    const response = await axios.get(
      `https://api.openweathermap.org/data/2.5/weather?q=${city}&appid=${apiKey}&units=metric`
    );
    const weatherData = response.data;
    res.status(200).json(weatherData);
  } catch (error) {
    console.error('Error fetching weather data:', error);
    res.status(500).json({ error: 'Failed to fetch weather data' });
  }
}

This code does the following:

  • Imports the axios library.
  • Defines an asynchronous function handler that will handle the API request.
  • Retrieves the city parameter from the query string (e.g., /api/weather?city=London).
  • Retrieves the API key from the environment variables.
  • Checks if the city parameter is provided. If not, it returns an error.
  • Uses axios to make a GET request to the OpenWeatherMap API, including the city and API key. The `units=metric` parameter is used to get the temperature in Celsius.
  • If the request is successful, it sends the weather data in JSON format.
  • If there’s an error, it logs the error and returns an error message.

5. Building the UI (Frontend)

Now, let’s build the user interface for our weather app. Open pages/index.js and replace the existing code with the following:

// pages/index.js
import { useState } from 'react';
import axios from 'axios';

export default function Home() {
  const [city, setCity] = useState('');
  const [weatherData, setWeatherData] = useState(null);
  const [error, setError] = useState(null);
  const [loading, setLoading] = useState(false);

  const handleInputChange = (event) => {
    setCity(event.target.value);
    setError(null);
  };

  const handleSubmit = async (event) => {
    event.preventDefault();
    setLoading(true);
    setError(null);
    setWeatherData(null);

    try {
      const response = await axios.get(`/api/weather?city=${city}`);
      setWeatherData(response.data);
    } catch (error) {
      setError(error.response?.data?.message || 'Failed to fetch weather data');
    } finally {
      setLoading(false);
    }
  };

  return (
    <div className="container">
      <h1>Weather App</h1>
      <form onSubmit={handleSubmit} className="search-form">
        <input
          type="text"
          placeholder="Enter city name"
          value={city}
          onChange={handleInputChange}
          className="search-input"
        />
        <button type="submit" disabled={loading} className="search-button">
          {loading ? 'Loading...' : 'Search'}
        </button>
      </form>
      {error && <p className="error">{error}</p>}
      {weatherData && (
        <div className="weather-info">
          <h2>{weatherData.name}, {weatherData.sys.country}</h2>
          <p>Temperature: {weatherData.main.temp} °C</p>
          <p>Description: {weatherData.weather[0].description}</p>
          <p>Humidity: {weatherData.main.humidity}%</p>
          <p>Wind Speed: {weatherData.wind.speed} m/s</p>
        </div>
      )}
    </div>
  );
}

Let’s break down this code:

  • Import Statements: Imports useState from React and axios.
  • State Variables:
    • city: Stores the city name entered by the user.
    • weatherData: Stores the weather data fetched from the API.
    • error: Stores any error messages.
    • loading: A boolean to indicate if the data is being fetched.
  • handleInputChange Function: Updates the city state when the user types in the input field and resets the error.
  • handleSubmit Function:
    • Prevents the default form submission behavior.
    • Sets loading to true.
    • Resets the error and the weather data.
    • Makes a GET request to the /api/weather endpoint with the city name.
    • If the request is successful, it updates the weatherData state.
    • If there’s an error, it updates the error state.
    • Finally, sets loading to false.
  • JSX Structure:
    • Renders a heading, a form for entering the city, and a submit button.
    • Displays an error message if there’s an error.
    • If weather data is available, it displays the city name, temperature, description, humidity, and wind speed.

6. Styling Your App (Optional)

To make your app look more appealing, you can add some CSS styling. Create a file named styles/Home.module.css (or you can add the styles directly in the pages/index.js file, but separating your styles is generally a good practice). Add the following CSS:

/* styles/Home.module.css */
.container {
  display: flex;
  flex-direction: column;
  align-items: center;
  padding: 20px;
  font-family: sans-serif;
}

h1 {
  margin-bottom: 20px;
}

.search-form {
  display: flex;
  margin-bottom: 20px;
}

.search-input {
  padding: 10px;
  border: 1px solid #ccc;
  border-radius: 4px;
  margin-right: 10px;
  font-size: 16px;
}

.search-button {
  padding: 10px 20px;
  background-color: #0070f3;
  color: white;
  border: none;
  border-radius: 4px;
  cursor: pointer;
  font-size: 16px;
}

.search-button:disabled {
  background-color: #ccc;
  cursor: not-allowed;
}

.error {
  color: red;
  margin-bottom: 10px;
}

.weather-info {
  border: 1px solid #ccc;
  padding: 20px;
  border-radius: 4px;
  text-align: center;
}

Import this CSS file into your pages/index.js file by adding the following line at the top of the file:

import styles from '../styles/Home.module.css'

And apply the CSS classes to your HTML elements. For example, in your pages/index.js file, modify the return statement to use the styles:

<div className={styles.container}>
  <h1>Weather App</h1>
  <form onSubmit={handleSubmit} className={styles.searchForm}>
    <input
      type="text"
      placeholder="Enter city name"
      value={city}
      onChange={handleInputChange}
      className={styles.searchInput}
    />
    <button type="submit" disabled={loading} className={styles.searchButton}>
      {loading ? 'Loading...' : 'Search'}
    </button>
  </form>
  {error && <p className={styles.error}>{error}</p>}
  {weatherData && (
    <div className={styles.weatherInfo}>
      <h2>{weatherData.name}, {weatherData.sys.country}</h2>
      <p>Temperature: {weatherData.main.temp} °C</p>
      <p>Description: {weatherData.weather[0].description}</p>
      <p>Humidity: {weatherData.main.humidity}%</p>
      <p>Wind Speed: {weatherData.wind.speed} m/s</p>
    </div>
  )}
</div>

7. Running Your Application

Now that you’ve completed the code, it’s time to run your weather app. In your terminal, run the following command:

npm run dev

This will start the Next.js development server. Open your browser and go to http://localhost:3000. You should see your weather app!

Common Mistakes and How to Fix Them

Here are some common mistakes and how to avoid them:

  • API Key Issues:
    • Mistake: Forgetting to include your API key in the API request or committing it directly into your code.
    • Fix: Always store your API key in environment variables (.env.local) and access it using process.env.YOUR_API_KEY.
  • CORS Errors:
    • Mistake: Getting CORS (Cross-Origin Resource Sharing) errors, which can occur when your frontend tries to access an API from a different domain.
    • Fix: Your Next.js API routes act as a proxy. Make sure you are making the API request from your Next.js API route (e.g., /api/weather) and not directly from the client-side. The API route will handle the request to the external API. If you are still encountering CORS issues, check the API provider’s documentation for CORS configuration.
  • Incorrect API Endpoint:
    • Mistake: Using an incorrect API endpoint or parameters in your API request.
    • Fix: Double-check the OpenWeatherMap API documentation for the correct endpoint and parameters. Ensure you’re sending the correct city name and API key.
  • Error Handling:
    • Mistake: Not handling errors properly, leading to a broken user experience.
    • Fix: Implement proper error handling using try...catch blocks and display informative error messages to the user. Also, check the error.response object for more detailed error information.
  • Typos:
    • Mistake: Simple typos in the code.
    • Fix: Carefully review your code for typos in variable names, function names, and API endpoint URLs. Use a code editor with good syntax highlighting and error checking.

Key Takeaways

This tutorial demonstrated how to build a basic weather application using Next.js. You’ve learned how to:

  • Set up a Next.js project.
  • Use environment variables to securely store API keys.
  • Create API routes to fetch data from an external API.
  • Build a simple user interface using React components.
  • Handle user input and display data.
  • Implement basic error handling.

By following these steps, you’ve created a functional weather application and gained valuable experience with Next.js and web development principles. This project provides a solid foundation for building more complex and feature-rich applications. With this knowledge, you can extend your app with features such as:

  • Displaying weather forecasts for multiple days.
  • Adding a map to show the location of the city.
  • Allowing users to save their favorite cities.
  • Implementing more advanced styling and UI components.

Optional FAQ

Here are some frequently asked questions:

  1. Can I use a different weather API? Yes, you can. Simply replace the OpenWeatherMap API endpoint and adapt the code to handle the specific API’s response format.
  2. How can I deploy this app? You can deploy your Next.js app to platforms like Vercel, Netlify, or AWS. Vercel is particularly well-suited for Next.js apps.
  3. How can I improve the UI? You can use a UI framework like Material UI, Chakra UI, or Tailwind CSS to create a more polished and responsive user interface.
  4. How can I add more features? Consider adding features like: a search history, different units of measurement (Celsius/Fahrenheit), a more detailed weather description with icons, and a dark mode.
  5. Where can I find more information about Next.js? The official Next.js documentation is an excellent resource: nextjs.org/docs.

Building this weather app is just the beginning. The skills you’ve acquired can be applied to many other projects. Keep experimenting, learning, and building. The world of web development is constantly evolving, so stay curious and continue to explore new technologies and techniques.