Next.js: Build a Simple Interactive Random Quote Generator

Written by

in

In the digital age, we’re constantly bombarded with information. Sometimes, what we need is a little inspiration, a thought-provoking quote to kickstart our day or provide a moment of reflection. This tutorial will guide you through building a simple, yet engaging, Random Quote Generator using Next.js. This project isn’t just about coding; it’s about creating something that can bring a smile to someone’s face, offer a moment of pause, or simply provide a bit of daily motivation. We’ll explore fundamental Next.js concepts while crafting a practical and user-friendly application.

Why Build a Random Quote Generator?

Beyond the motivational aspect, building a Random Quote Generator is a fantastic learning opportunity. It allows you to:

  • Practice with React and Next.js: You’ll reinforce your understanding of components, state management, and event handling.
  • Work with API calls: You’ll learn how to fetch data from an external API, a crucial skill for any web developer.
  • Understand basic styling: You’ll get hands-on experience with styling your application to create a visually appealing user interface.
  • Deploy a simple application: You’ll learn how to deploy your Next.js application, making it accessible to anyone with a web browser.

This project is perfect for beginners and intermediate developers looking to solidify their Next.js skills and build something useful.

Prerequisites

Before we dive in, ensure you have the following:

  • Node.js and npm (or yarn): Installed on your computer.
  • A basic understanding of JavaScript and React: Familiarity with components, props, and state will be helpful.
  • A code editor: Such as VS Code, Sublime Text, or Atom.

Setting Up Your Next.js Project

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

npx create-next-app random-quote-generator

This command will create a new directory called random-quote-generator and install all the necessary dependencies. Navigate into your project directory:

cd random-quote-generator

Now, start the development server:

npm run dev

This will start the development server, and you can access your application at http://localhost:3000. You should see the default Next.js welcome page.

Project Structure

Next.js follows a structured file system. Here’s what our project structure will look like:

random-quote-generator/
├── pages/
│   └── index.js       # Our main page
├── styles/
│   └── globals.css    # Global styles
├── package.json       # Project dependencies and scripts
└── next.config.js     # Next.js configuration

Fetching Quotes from an API

We’ll use a free and publicly available API to fetch our quotes. There are several options available; for this tutorial, we’ll use Quotable API. This API provides random quotes in a JSON format. Let’s create a function to fetch the quotes.

Open pages/index.js and replace the existing code with the following:

import { useState, useEffect } from 'react';

export default function Home() {
  const [quote, setQuote] = useState('');
  const [author, setAuthor] = useState('');
  const [isLoading, setIsLoading] = useState(true);

  useEffect(() => {
    const fetchQuote = async () => {
      setIsLoading(true);
      try {
        const response = await fetch('https://api.quotable.io/random');
        const data = await response.json();
        setQuote(data.content);
        setAuthor(data.author);
      } catch (error) {
        console.error('Error fetching quote:', error);
        setQuote('Failed to fetch quote.');
        setAuthor('');
      } finally {
        setIsLoading(false);
      }
    };

    fetchQuote();
  }, []);

  return (
    <div>
      <p>{isLoading ? 'Loading...' : `"${quote}"`}</p>
      <p>{isLoading ? '' : `- ${author}`}</p>
    </div>
  );
}

Let’s break down this code:

  • Import statements: We import useState and useEffect from React.
  • State variables:
    • quote: Stores the quote text.
    • author: Stores the author of the quote.
    • isLoading: A boolean to indicate if the data is being fetched.
  • useEffect hook: This hook runs after the component renders. It fetches the quote from the API using the fetchQuote function. The empty dependency array [] ensures that this effect runs only once, when the component mounts.
  • fetchQuote function:
    • Sets isLoading to true before fetching.
    • Uses the fetch API to make a request to the Quotable API.
    • Parses the response as JSON.
    • Updates the quote and author state variables with the data from the API.
    • Includes a try...catch block to handle potential errors during the API call.
    • Uses a finally block to set isLoading to false, regardless of success or failure.
  • JSX: Renders the quote and author, or a loading message while the data is being fetched.

Now, save the file and check your browser. You should see a random quote and its author displayed on the page. If you refresh the page, a new quote should appear.

Adding a Button to Generate New Quotes

Currently, the quote changes only when the page reloads. Let’s add a button that allows the user to generate a new quote with a click. Modify the pages/index.js file as follows:

import { useState, useEffect } from 'react';

export default function Home() {
  const [quote, setQuote] = useState('');
  const [author, setAuthor] = useState('');
  const [isLoading, setIsLoading] = useState(true);

  const fetchQuote = async () => {
    setIsLoading(true);
    try {
      const response = await fetch('https://api.quotable.io/random');
      const data = await response.json();
      setQuote(data.content);
      setAuthor(data.author);
    } catch (error) {
      console.error('Error fetching quote:', error);
      setQuote('Failed to fetch quote.');
      setAuthor('');
    } finally {
      setIsLoading(false);
    }
  };

  useEffect(() => {
    fetchQuote();
  }, []);

  return (
    <div>
      <p>{isLoading ? 'Loading...' : `"${quote}"`}</p>
      <p>{isLoading ? '' : `- ${author}`}</p>
      <button onClick={fetchQuote} disabled={isLoading}>New Quote</button>
    </div>
  );
}

Changes:

  • We’ve moved the fetchQuote function outside of the useEffect hook so that we can call it from the button’s onClick handler.
  • Added a <button> element.
  • The onClick handler calls the fetchQuote function.
  • The button is disabled while isLoading is true to prevent multiple API calls at once.

Now, when you click the “New Quote” button, a new quote should appear.

Styling the Quote Generator

Let’s add some basic styling to improve the appearance of our quote generator. We’ll use CSS modules. Create a file named styles/QuoteGenerator.module.css and add the following styles:

.container {
  display: flex;
  flex-direction: column;
  align-items: center;
  justify-content: center;
  min-height: 100vh;
  padding: 20px;
  font-family: sans-serif;
  text-align: center;
}

.quote {
  font-size: 1.5rem;
  margin-bottom: 20px;
  font-style: italic;
}

.author {
  font-size: 1rem;
  color: #555;
}

.button {
  background-color: #4CAF50;
  border: none;
  color: white;
  padding: 10px 20px;
  text-align: center;
  text-decoration: none;
  display: inline-block;
  font-size: 16px;
  margin-top: 20px;
  cursor: pointer;
  border-radius: 5px;
}

.button:hover {
  background-color: #3e8e41;
}

.loading {
  font-style: italic;
  color: #777;
}

Now, import this CSS module into your pages/index.js file and apply the styles:

import { useState, useEffect } from 'react';
import styles from '../styles/QuoteGenerator.module.css';

export default function Home() {
  const [quote, setQuote] = useState('');
  const [author, setAuthor] = useState('');
  const [isLoading, setIsLoading] = useState(true);

  const fetchQuote = async () => {
    setIsLoading(true);
    try {
      const response = await fetch('https://api.quotable.io/random');
      const data = await response.json();
      setQuote(data.content);
      setAuthor(data.author);
    } catch (error) {
      console.error('Error fetching quote:', error);
      setQuote('Failed to fetch quote.');
      setAuthor('');
    } finally {
      setIsLoading(false);
    }
  };

  useEffect(() => {
    fetchQuote();
  }, []);

  return (
    <div className={styles.container}>
      <div className={styles.quote}>{isLoading ? 'Loading...' : `"${quote}"`}</div>
      <div className={styles.author}>{isLoading ? '' : `- ${author}`}</div>
      <button className={styles.button} onClick={fetchQuote} disabled={isLoading}>New Quote</button>
    </div>
  );
}

Let’s explain what we did:

  • Imported the CSS module: import styles from '../styles/QuoteGenerator.module.css';
  • Used the CSS classes in the JSX: <div className={styles.container}>, etc.

Now, your quote generator should have a much better look. You can customize the styles further to match your preferences.

Handling Errors

In the current implementation, if the API call fails, we display a generic “Failed to fetch quote.” message. Let’s enhance this by providing more informative error handling. We can display an error message to the user and perhaps log the error to the console for debugging.

Modify the fetchQuote function in pages/index.js:

const fetchQuote = async () => {
  setIsLoading(true);
  try {
    const response = await fetch('https://api.quotable.io/random');
    if (!response.ok) {
      throw new Error(`HTTP error! Status: ${response.status}`);
    }
    const data = await response.json();
    setQuote(data.content);
    setAuthor(data.author);
  } catch (error) {
    console.error('Error fetching quote:', error);
    setQuote('Failed to fetch quote. Please try again later.');
    setAuthor('');
  } finally {
    setIsLoading(false);
  }
};

Changes:

  • We added a check using response.ok to ensure the HTTP request was successful. If the response status is not in the 200-299 range, it throws an error.
  • The error message displayed to the user is more informative.

Now, if the API call fails (e.g., due to network issues), the user will see a more user-friendly error message.

Deploying Your Quote Generator

Once you’re satisfied with your quote generator, it’s time to deploy it so others can enjoy it. Next.js makes deployment straightforward. One of the easiest ways to deploy a Next.js application is with Vercel, the platform created by the Next.js team. If you haven’t already, sign up for a free Vercel account at Vercel.

Here’s how to deploy:

  1. Push your code to a Git repository: If you haven’t already, initialize a Git repository in your project directory (git init) and push your code to a platform like GitHub, GitLab, or Bitbucket.
  2. Import your project into Vercel:
    • Log in to your Vercel account.
    • Click “Add New Project.”
    • Select the Git repository where your code is hosted.
    • Vercel will automatically detect that it’s a Next.js project and configure the build settings.
    • Click “Deploy.”
  3. Access your deployed application: Vercel will provide a URL for your deployed application. You can share this URL with others.

That’s it! Your Random Quote Generator is now live and accessible on the web.

Common Mistakes and How to Fix Them

Here are some common mistakes and how to avoid them:

  • Incorrect API URL: Double-check that the API URL is correct. A typo can prevent the API call from working.
  • CORS errors: If you encounter CORS (Cross-Origin Resource Sharing) errors, the API might not allow requests from your domain. This is less likely with public APIs, but it’s something to be aware of. You might need to configure CORS settings on the API server or use a proxy.
  • Not handling errors: Always include error handling (try...catch blocks) when making API calls. This ensures your application gracefully handles unexpected situations.
  • Forgetting to install dependencies: Make sure you run npm install or yarn install in your project directory to install all the required dependencies.
  • Incorrect file paths: When importing CSS modules or other files, make sure the file paths are correct.

Key Takeaways

  • You learned how to fetch data from an external API using fetch.
  • You gained experience with React’s useState and useEffect hooks.
  • You implemented a user-friendly interface with a button.
  • You learned how to style your application using CSS modules.
  • You deployed your Next.js application to Vercel.

FAQ

  1. Can I use a different API for quotes?

    Yes, absolutely! There are many free quote APIs available. Just find one that provides quotes in a JSON format, and update the API URL in your code. Some popular alternatives include: Forismatic API, Quotes on Design API.

  2. How can I add more features?

    You can add features like:

    • A counter for the number of quotes generated.
    • The ability to share quotes on social media.
    • Different categories of quotes.
    • User preferences (e.g., dark/light mode).
  3. How do I handle API rate limits?

    Some APIs have rate limits, meaning you can only make a certain number of requests within a specific time frame. If you exceed the rate limit, the API might block your requests. To handle this, you can implement strategies like:

    • Caching quotes locally to reduce the number of API calls.
    • Implementing a delay between API requests.
    • Using a proxy server if you need to make a large number of requests.
  4. What are CSS modules and why are they used?

    CSS modules are a way to scope CSS styles to individual components. They automatically generate unique class names, preventing style conflicts between different components in your application. This makes your CSS more maintainable and easier to manage, especially in larger projects.

Building a Random Quote Generator is a perfect stepping stone into the world of web development. It combines fundamental concepts with a dash of creativity, allowing you to learn and grow your skills while creating something enjoyable. As you continue to explore Next.js and React, remember that the most important thing is to experiment, practice, and never stop learning. Each project you undertake, no matter how small, adds to your knowledge and confidence. Embrace the challenges, learn from your mistakes, and enjoy the journey of becoming a proficient web developer. The ability to create applications that bring joy, offer insight, or solve everyday problems is a rewarding skill, and this simple project is a great starting point for that journey.