Build a Simple Next.js Interactive Web-Based Cryptocurrency News Aggregator

Written by

in

In the fast-paced world of cryptocurrencies, staying informed is crucial. The market fluctuates wildly, and news can break at any moment, impacting prices and investment strategies. Building a cryptocurrency news aggregator with Next.js is a fantastic project for developers looking to enhance their skills. This tutorial will guide you through creating a simple, yet functional, web application that fetches and displays real-time cryptocurrency news from various sources.

Why Build a Cryptocurrency News Aggregator?

As a senior software engineer and technical content writer, I often emphasize the importance of practical projects. This project offers several benefits:

  • Real-World Application: Cryptocurrency is a popular and relevant topic, making this project immediately applicable.
  • API Integration: You’ll learn how to fetch data from external APIs, a fundamental skill for web development.
  • Front-End Development: You’ll practice building user interfaces with React and Next.js.
  • State Management: You’ll manage and update data efficiently.
  • SEO Optimization: You’ll learn to create SEO-friendly websites.

This project is perfect for beginners to intermediate developers who want to learn Next.js and improve their front-end development skills. By the end, you’ll have a fully functional news aggregator that you can customize and expand.

Prerequisites

Before we dive in, ensure you have the following:

  • Node.js and npm (or yarn): Installed on your computer.
  • Basic understanding of JavaScript and React: Familiarity with components, props, and state.
  • Text Editor or IDE: Such as VS Code, Sublime Text, or Atom.
  • API Key (Optional): While some news APIs are free, they may require an API key. We’ll explore free options.

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 crypto-news-aggregator
cd crypto-news-aggregator

This command creates a new Next.js project named “crypto-news-aggregator” and navigates you into the project directory.

Project Structure

Your project directory should look something like this:


crypto-news-aggregator/
├── node_modules/
├── pages/
│   ├── _app.js
│   ├── index.js
│   └── ...
├── public/
│   └── ...
├── .gitignore
├── next.config.js
├── package-lock.json
├── package.json
└── README.md
  • pages/: This directory contains your application’s pages. Each file in this directory represents a route.
  • public/: This directory is for static assets like images, fonts, etc.
  • next.config.js: This file is used for configuring Next.js.
  • package.json: This file contains your project’s dependencies and scripts.

Installing Dependencies

We’ll need to install a few dependencies for this project. We’ll use the following:

  • axios: For making API requests.
  • date-fns: For formatting dates.

Run the following command in your terminal:

npm install axios date-fns

Fetching Cryptocurrency News: Choosing an API

To get cryptocurrency news, we need an API that provides news articles. Several free and paid options are available. Here’s an example using the News API (you’ll need to sign up for a free API key):

Note: You can also use other free news APIs if you prefer, such as CryptoPanic or CoinDesk API, making sure to adapt the code accordingly.

For this tutorial, let’s assume we’re using the News API. Sign up for a free account and get your API key. We’ll store the API key in our environment variables.

Creating Environment Variables

Create a file named .env.local in the root of your project. Add your API key:

NEWS_API_KEY=YOUR_API_KEY

Important: Replace YOUR_API_KEY with your actual API key.

Next.js automatically loads environment variables from the .env.local file during development. You can access these variables in your code using process.env.NEWS_API_KEY.

Creating the News Fetching Function

Let’s create a function to fetch news articles. We’ll create a new file called utils/newsApi.js in your project. This file will handle the API request and data processing.

// utils/newsApi.js
import axios from 'axios';

const API_KEY = process.env.NEWS_API_KEY;
const BASE_URL = 'https://newsapi.org/v2/everything';

async function getNews(query) {
  try {
    const response = await axios.get(BASE_URL, {
      params: {
        q: query, // Search query (e.g., "cryptocurrency", "bitcoin")
        apiKey: API_KEY,
        sortBy: 'publishedAt',
        pageSize: 10, // Number of articles to retrieve
      },
    });
    return response.data.articles;
  } catch (error) {
    console.error('Error fetching news:', error);
    return [];
  }
}

export default getNews;

Explanation:

  • Import axios: We import the axios library to make HTTP requests.
  • API_KEY and BASE_URL: We define the API key and base URL from the News API.
  • getNews(query): This asynchronous function takes a search query as input (e.g., “cryptocurrency”).
  • axios.get(): We use axios to make a GET request to the News API.
  • params: We pass parameters to the API, including the search query, API key, sorting criteria, and page size.
  • Error Handling: We use a try…catch block to handle any errors during the API request.

Building the News Component

Now, let’s create a React component to display the news articles. We’ll create a new file called components/NewsArticle.js in your project.


// components/NewsArticle.js
import React from 'react';
import { format } from 'date-fns';

function NewsArticle({ article }) {
  if (!article) {
    return null;
  }

  const { title, url, urlToImage, publishedAt, source, description } = article;

  const formattedDate = format(new Date(publishedAt), 'MMMM dd, yyyy - HH:mm');

  return (
    <div>
      {urlToImage && (
        <img src="{urlToImage}" alt="{title}" />
      )}
      <h3>
        <a href="{url}" target="_blank" rel="noopener noreferrer">
          {title}
        </a>
      </h3>
      <p>{source?.name} - {formattedDate}</p>
      <p>{description}</p>
    </div>
  );
}

export default NewsArticle;

Explanation:

  • Import React: We import React for creating the component.
  • format: We import `format` from `date-fns` to format the date.
  • NewsArticle({ article }): This functional component receives an article object as a prop.
  • Destructuring: We destructure the article object to extract the necessary properties.
  • Formatted Date: We use date-fns to format the published date.
  • JSX: We return JSX to render the news article, including the title, image, source, and description.
  • Conditional Rendering: We use conditional rendering to display the image only if a URL to the image is available.

Creating the Main Page (index.js)

Now, let’s modify the pages/index.js file to fetch and display the news articles.


// pages/index.js
import React, { useState, useEffect } from 'react';
import getNews from '../utils/newsApi';
import NewsArticle from '../components/NewsArticle';

function HomePage() {
  const [news, setNews] = useState([]);
  const [loading, setLoading] = useState(true);
  const [error, setError] = useState(null);
  const [searchQuery, setSearchQuery] = useState('cryptocurrency');

  useEffect(() => {
    const fetchNews = async () => {
      setLoading(true);
      setError(null);
      try {
        const articles = await getNews(searchQuery);
        setNews(articles);
      } catch (err) {
        setError(err);
      } finally {
        setLoading(false);
      }
    };

    fetchNews();
  }, [searchQuery]);

  const handleSearch = (event) => {
    event.preventDefault();
    const query = event.target.search.value;
    setSearchQuery(query);
  };

  return (
    <div>
      <h1>Cryptocurrency News Aggregator</h1>
      
        
        <button type="submit">Search</button>
      

      {loading && <p>Loading news...</p>}
      {error && <p>Error fetching news: {error.message}</p>}
      <div>
        {news.map((article) => (
          
        ))}
      </div>
    </div>
  );
}

export default HomePage;

Explanation:

  • Import Statements: We import React, useState, useEffect, the getNews function, and the NewsArticle component.
  • State Variables:
    • news: An array to store the fetched news articles.
    • loading: A boolean to indicate whether the data is being fetched.
    • error: To store any errors that occur during the fetch.
    • searchQuery: To store the search query.
  • useEffect Hook:
    • This hook runs when the component mounts and whenever the searchQuery changes.
    • Inside the hook, an async function fetchNews is defined to fetch the news articles using the getNews function.
    • We set loading to true before fetching the data.
    • We call the getNews function with the searchQuery.
    • We update the news state with the fetched articles.
    • We set loading to false after the data is fetched (or if an error occurs).
    • Error handling is included to catch any errors during the fetch.
  • handleSearch Function:
    • This function is called when the search form is submitted.
    • It prevents the default form submission behavior.
    • It updates the searchQuery state with the value entered in the search input.
  • JSX:
    • We render a heading, a search form, and a conditional loading message.
    • If there is an error, an error message is displayed.
    • We map over the news array and render a NewsArticle component for each article.

Styling the Application

To make the application visually appealing, let’s add some basic styling. Create a file named styles/globals.css in your project, and add the following CSS:


/* styles/globals.css */
body {
  font-family: sans-serif;
  margin: 0;
  padding: 0;
  background-color: #f4f4f4;
}

.container {
  max-width: 960px;
  margin: 20px auto;
  padding: 20px;
  background-color: #fff;
  border-radius: 8px;
  box-shadow: 0 0 10px rgba(0, 0, 0, 0.1);
}

h1 {
  text-align: center;
  color: #333;
}

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

.search-form input[type="text"] {
  padding: 10px;
  border: 1px solid #ccc;
  border-radius: 4px;
  margin-right: 10px;
  width: 300px;
}

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

.news-grid {
  display: grid;
  grid-template-columns: repeat(auto-fill, minmax(300px, 1fr));
  gap: 20px;
}

.news-article {
  border: 1px solid #ddd;
  padding: 15px;
  border-radius: 8px;
  background-color: #f9f9f9;
}

.news-image {
  width: 100%;
  height: auto;
  margin-bottom: 10px;
  border-radius: 4px;
}

.news-title {
  margin-top: 0;
  font-size: 1.2rem;
}

.news-title a {
  color: #0070f3;
  text-decoration: none;
}

.news-title a:hover {
  text-decoration: underline;
}

.news-source {
  color: #777;
  font-size: 0.8rem;
  margin-bottom: 5px;
}

.news-description {
  margin-bottom: 0;
}

Explanation:

  • Basic Styling: This CSS provides basic styling for the body, container, headings, search form, and news articles.
  • Grid Layout: The news-grid class uses a CSS grid to display the news articles in a responsive layout.
  • Responsiveness: The grid-template-columns: repeat(auto-fill, minmax(300px, 1fr)); ensures that the articles adapt to different screen sizes.
  • Visual Appeal: The styling includes padding, borders, and background colors to make the application more visually appealing.

To apply these styles, import the globals.css file in your _app.js file:


// pages/_app.js
import '../styles/globals.css';

function MyApp({ Component, pageProps }) {
  return ;
}

export default MyApp;

Running Your Application

Now that you’ve completed the code, you can run your Next.js application by running the following command in your terminal:

npm run dev

This command starts the development server. Open your browser and go to http://localhost:3000 to see your cryptocurrency news aggregator in action.

Common Mistakes and Troubleshooting

Here are some common mistakes and how to fix them:

  • API Key Issues:
    • Problem: News not loading, or you see an error related to the API key.
    • Solution: Double-check your API key in the .env.local file and ensure it matches the key provided by the News API. Also, ensure you’ve restarted your development server after adding or changing the API key.
  • CORS Errors:
    • Problem: You might encounter CORS (Cross-Origin Resource Sharing) errors if the API doesn’t allow requests from your domain.
    • Solution: This is less likely in a development environment. If it occurs, check the API’s documentation to see if they provide a way to enable CORS for your domain or try a proxy server.
  • Incorrect API Endpoint:
    • Problem: News is not fetched, or the application throws an error.
    • Solution: Double-check the API endpoint URL and ensure it’s correct. Also, verify that the query parameters (e.g., “q”, “apiKey”) are correctly formatted.
  • Data Not Displaying:
    • Problem: News articles are fetched, but not displayed.
    • Solution: Inspect your browser’s developer console (usually by pressing F12) to check for JavaScript errors. Ensure the data being fetched is in the expected format. Verify that you are correctly mapping through the data and rendering the NewsArticle component.
  • Environment Variables Not Loading:
    • Problem: The API key is not being read from the .env.local file.
    • Solution: Make sure the file is correctly named (.env.local, not .env), and that you have restarted the development server after creating or modifying the file. Also, verify that you are accessing the environment variable correctly (e.g., process.env.NEWS_API_KEY).

Key Takeaways

This project has taught you how to:

  • Create a Next.js project.
  • Fetch data from an external API.
  • Use environment variables.
  • Create and use React components.
  • Manage state with the useState and useEffect hooks.
  • Implement basic styling.

You can expand this project further by adding features such as:

  • More News Sources: Integrate with other news APIs.
  • Filtering and Sorting: Allow users to filter and sort news articles by date, source, etc.
  • User Interface Enhancements: Improve the design and user experience.
  • Error Handling: Implement more robust error handling.
  • Caching: Implement caching to reduce API calls and improve performance.

Frequently Asked Questions (FAQ)

  1. Can I use a different news API?

    Yes, you can. You’ll need to sign up for an API key from a different provider and modify the utils/newsApi.js file to use the new API’s endpoints and data structures.

  2. How can I deploy this application?

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

  3. How do I add more styling?

    You can add more styling by modifying the styles/globals.css file or by using CSS-in-JS solutions like styled-components or Emotion.

  4. How can I make the app responsive?

    The provided CSS includes a basic responsive design. You can further enhance responsiveness by using media queries in your CSS to adjust the layout for different screen sizes.

  5. What if the API I choose has rate limits?

    If your chosen API has rate limits, implement strategies like caching, limiting the number of API calls, and displaying appropriate messages to the user if the rate limit is exceeded. Consider adding a backend to handle API requests and cache the responses.

This cryptocurrency news aggregator is a stepping stone to building more complex and feature-rich applications. By understanding the fundamentals demonstrated in this tutorial, you are well-equipped to tackle more challenging projects and further hone your skills as a web developer. Keep experimenting, keep learning, and don’t hesitate to explore new technologies and approaches to enhance your creations. With consistent practice and dedication, you’ll continue to grow as a proficient software engineer.