Next.js: Build a Simple Interactive Weather App

Written by

in

In today’s fast-paced digital world, weather information is more accessible than ever. From checking the forecast before heading out to tracking severe weather alerts, we rely on weather data daily. Building a weather application might seem complex, but with Next.js, it can be a manageable and rewarding project, perfect for developers looking to expand their skillset. This tutorial guides you through creating a simple, interactive weather app using Next.js, providing a practical introduction to fetching data from APIs, handling user input, and displaying dynamic content. We’ll cover everything from setting up your development environment to deploying your finished application.

Why Build a Weather App?

Creating a weather app offers numerous benefits for developers. It’s an excellent way to:

  • Learn API Integration: You’ll gain hands-on experience fetching data from external APIs, a crucial skill for modern web development.
  • Understand State Management: You’ll work with state management to handle user input and update the UI dynamically.
  • Practice UI Design: You can experiment with creating a user-friendly interface to display weather information effectively.
  • Master Next.js Fundamentals: You’ll reinforce your understanding of Next.js concepts like routing, component-based architecture, and server-side rendering (SSR).

Moreover, building this app can be a fun and engaging project that allows you to apply your skills in a practical context. As you progress, you’ll not only learn how to build a weather app but also gain valuable insights into the broader landscape of web development.

Prerequisites

Before we begin, ensure you have the following:

  • Node.js and npm: Install Node.js and npm (Node Package Manager) on your system. You can download them from the official Node.js website.
  • Basic JavaScript Knowledge: Familiarity with JavaScript fundamentals, including variables, functions, and working with objects and arrays.
  • Understanding of React: Since Next.js is built on React, a basic understanding of React components, JSX, and props will be helpful.
  • Text Editor or IDE: A code editor like Visual Studio Code, Sublime Text, or Atom.

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 sets up a new Next.js project named “weather-app.” The `cd weather-app` command navigates into your project directory. Now, start the development server:

npm run dev

Open your browser and go to `http://localhost:3000`. You should see the default Next.js welcome page. This confirms your project setup is successful.

Installing Dependencies

For this project, we’ll need to install a few dependencies. Open your terminal in the project directory and run:

npm install axios react-icons

Here’s what these dependencies do:

  • axios: A popular library for making HTTP requests to fetch data from the weather API.
  • react-icons: A library providing readily available icons for the user interface.

Choosing a Weather API

We’ll use a free weather API to fetch weather data. There are several options available. For this tutorial, we will use the OpenWeatherMap API, as it offers a free tier that provides sufficient functionality for our needs.

1. Sign Up for an API Key: Go to the OpenWeatherMap website and sign up for a free account. After signing up, you’ll receive an API key. Keep this key safe, as you’ll need it to access the weather data.

2. API Endpoint: The API endpoint we’ll use to fetch weather data by city name is: `https://api.openweathermap.org/data/2.5/weather?q={city name}&appid={API key}&units=metric`

Replace `{city name}` with the name of the city you want to search for, and `{API key}` with your API key. The `units=metric` parameter ensures the temperature is displayed in Celsius.

Building the Weather App Components

Now, let’s create the components for our weather app. We’ll start with a `Search` component for handling user input and a `WeatherDisplay` component to display the weather information. Create a `components` directory in your project’s root directory. Inside this directory, create two files:

  • `Search.js`
  • `WeatherDisplay.js`

Search Component (Search.js)

This component will contain an input field for the user to enter a city name and a button to trigger the weather search. Here’s the code:

import React, { useState } from 'react';

function Search({ onSearch }) {
  const [city, setCity] = useState('');

  const handleSubmit = (e) => {
    e.preventDefault();
    if (city.trim() !== '') {
      onSearch(city);
      setCity(''); // Clear the input field after search
    }
  };

  return (
    <form onSubmit={handleSubmit} className="search-form">
      <input
        type="text"
        value={city}
        onChange={(e) => setCity(e.target.value)}
        placeholder="Enter city name"
        className="search-input"
      />
      <button type="submit" className="search-button">Search</button>
    </form>
  );
}

export default Search;

Explanation:

  • We import the `useState` hook from React to manage the city input’s state.
  • The `city` state variable stores the current city name entered by the user.
  • The `handleSubmit` function is called when the form is submitted. It prevents the default form submission behavior, calls the `onSearch` function (passed as a prop), and clears the input field.
  • The component renders a form with an input field and a submit button. The input field’s value is bound to the `city` state, and its `onChange` event updates the state.
  • The `onSearch` prop is a function that will be used to pass the city name to the parent component.

WeatherDisplay Component (WeatherDisplay.js)

This component will display the weather information fetched from the API. Here’s the code:

import React from 'react';

function WeatherDisplay({ weatherData, error, loading }) {
  if (loading) {
    return <p>Loading...</p>;
  }

  if (error) {
    return <p>Error: {error}</p>;
  }

  if (!weatherData) {
    return <p>Enter a city to see the weather.</p>;
  }

  return (
    <div className="weather-display">
      <h2>{weatherData.name}, {weatherData.sys.country}</h2>
      <p>Temperature: {weatherData.main.temp} °C</p>
      <p>Weather: {weatherData.weather[0].description}</p>
      <p>Humidity: {weatherData.main.humidity}%</p>
      <p>Wind Speed: {weatherData.wind.speed} m/s</p>
    </div>
  );
}

export default WeatherDisplay;

Explanation:

  • This component receives `weatherData`, `error`, and `loading` as props.
  • It displays a “Loading…” message while the data is being fetched.
  • If there’s an error, it displays the error message.
  • If `weatherData` is null or undefined, it displays a prompt to enter a city.
  • If `weatherData` is available, it renders the weather information, including city name, temperature, weather description, humidity, and wind speed.

Integrating Components in the Main Page

Now, let’s integrate these components into our main page (`pages/index.js`).

import React, { useState } from 'react';
import axios from 'axios';
import Search from '../components/Search';
import WeatherDisplay from '../components/WeatherDisplay';

function HomePage() {
  const [weatherData, setWeatherData] = useState(null);
  const [error, setError] = useState(null);
  const [loading, setLoading] = useState(false);

  const handleSearch = async (city) => {
    setLoading(true);
    setError(null);
    try {
      const apiKey = 'YOUR_API_KEY'; // Replace with your API key
      const response = await axios.get(
        `https://api.openweathermap.org/data/2.5/weather?q=${city}&appid=${apiKey}&units=metric`
      );
      setWeatherData(response.data);
    } catch (err) {
      setError(err.message);
    } finally {
      setLoading(false);
    }
  };

  return (
    <div className="container">
      <h1>Weather App</h1>
      <Search onSearch={handleSearch} />
      <WeatherDisplay weatherData={weatherData} error={error} loading={loading} />
    </div>
  );
}

export default HomePage;

Explanation:

  • We import `useState`, `axios`, `Search`, and `WeatherDisplay`.
  • We initialize `weatherData`, `error`, and `loading` states.
  • The `handleSearch` function is an asynchronous function that fetches weather data from the API:
    • It sets `loading` to `true` to indicate that data is being fetched.
    • It clears any previous error.
    • It uses `axios.get` to make a request to the OpenWeatherMap API. Replace `”YOUR_API_KEY”` with your actual API key.
    • If the request is successful, it updates the `weatherData` state.
    • If there’s an error, it updates the `error` state.
    • Finally, it sets `loading` to `false`.
  • We render the `Search` component, passing the `handleSearch` function as a prop.
  • We render the `WeatherDisplay` component, passing the `weatherData`, `error`, and `loading` states as props.

Styling the Application

Let’s add some basic styling to make the app more presentable. Create a file named `styles/Home.module.css` in your project’s root directory. Add the following CSS:


.container {
  display: flex;
  flex-direction: column;
  align-items: center;
  padding: 20px;
  font-family: sans-serif;
}

h1 {
  margin-bottom: 20px;
}

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

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

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

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

To apply these styles, import the CSS file into your `pages/index.js` file:

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

function HomePage() {
  // ... (rest of the code)

  return (
    <div className={styles.container}>
      <h1>Weather App</h1>
      <Search onSearch={handleSearch} />
      <WeatherDisplay weatherData={weatherData} error={error} loading={loading} />
    </div>
  );
}

export default HomePage;

Running the Application

Now, run your application using `npm run dev`. Open your browser and navigate to `http://localhost:3000`. You should see the weather app. Enter a city name in the input field, click the search button, and the app will display the weather information for that city.

Common Mistakes and Troubleshooting

Here are some common mistakes and how to fix them:

  • API Key Issues:
    • Incorrect API Key: Double-check that you’ve entered your API key correctly in the `handleSearch` function.
    • API Key Restrictions: Some API keys have usage limits. If you’ve exceeded your limit, you may receive an error. Consider upgrading your OpenWeatherMap plan or implementing rate limiting on your app.
  • CORS Errors:
    • Problem: You might encounter Cross-Origin Resource Sharing (CORS) errors if your API requests are blocked by the browser.
    • Solution: In a development environment, you might be able to disable CORS in your browser settings (not recommended for production). For a more robust solution, you can use a proxy server or deploy your application to a platform that handles CORS for you.
  • Incorrect City Name:
    • Problem: The API might not return data if the city name is misspelled or doesn’t exist.
    • Solution: Implement input validation to ensure the user enters a valid city name. You could also provide suggestions as the user types or handle the error gracefully by displaying a “City not found” message.
  • Data Not Displaying:
    • Problem: The weather data might not be displayed if the API request fails or if the component is not rendering the data correctly.
    • Solution: Use `console.log` statements to check the API response and ensure the data is being fetched and passed to the `WeatherDisplay` component. Review the component’s code to confirm that it correctly displays the data.

Key Takeaways

  • Component-Based Architecture: Next.js allows you to build applications using reusable components. This modular approach makes your code organized and maintainable.
  • API Integration: Fetching data from external APIs is a fundamental skill for web development. This project demonstrates how to make API calls using `axios`.
  • State Management: Handling user input and updating the UI dynamically is essential. We used the `useState` hook to manage the state of the city input and weather data.
  • Error Handling: Implementing error handling is important to provide a good user experience. We handled potential errors during the API request and displayed an appropriate error message.
  • Styling with CSS Modules: Next.js supports CSS Modules, which helps to scope your CSS styles to individual components, preventing style conflicts.

FAQ

Q: How can I deploy this application?

A: You can deploy your Next.js application to platforms like Vercel, Netlify, or AWS. These platforms offer easy deployment and hosting options.

Q: Can I add more features to this app?

A: Yes! You can enhance this app by adding features like:

  • Displaying weather forecasts for multiple days.
  • Adding a location search using geolocation.
  • Implementing a dark/light mode toggle.
  • Adding more detailed weather information (e.g., UV index, air quality).

Q: How do I handle different units (Celsius/Fahrenheit)?

A: You can add a setting in your app for the user to select their preferred temperature unit (Celsius or Fahrenheit). You’ll need to update your API request to include the appropriate `units` parameter (`metric` for Celsius, `imperial` for Fahrenheit). Then, convert the temperature value in your `WeatherDisplay` component.

Q: How can I improve the user interface?

A: You can improve the user interface by:

  • Using a CSS framework like Bootstrap, Tailwind CSS, or Material UI to create a more polished design.
  • Adding weather icons to visually represent the weather conditions.
  • Improving the layout and responsiveness of the app.
  • Using animations and transitions to enhance the user experience.

Q: Why is it important to use an API key?

A: API keys are used for authentication and authorization. They allow the API provider to identify and track the usage of their service. They are essential for:

  • Security: Protecting the API from unauthorized access.
  • Rate Limiting: Controlling the number of requests made by a user to prevent abuse.
  • Monitoring: Tracking usage and billing.

Always keep your API keys secure and never expose them directly in your client-side code, especially in a production environment. Consider using environment variables to store your API keys securely.

This project provides a solid foundation for building interactive web applications with Next.js. By understanding the concepts and following the steps outlined in this tutorial, you can create your own weather app and explore the possibilities of web development. From here, you can continue to expand your knowledge and skills, building more complex and feature-rich applications. Remember that practice is key, and the more projects you undertake, the more proficient you will become. As you experiment and learn, you’ll find yourself not just building applications but also building a deeper understanding of the technologies that power the web. With each line of code, you’re not just creating a weather app, you’re building your future in web development.