Build a Next.js Interactive Web-Based Random Quote Generator

Written by

in

In the digital age, we’re constantly bombarded with information, and sometimes, we need a little inspiration to get us through the day. What if you could build a simple, yet engaging, application that provides a daily dose of wisdom or a chuckle? This tutorial guides you through creating a Random Quote Generator using Next.js. This project will not only introduce you to fundamental Next.js concepts but also provide a practical application that you can customize and expand upon.

Why Build a Random Quote Generator?

A Random Quote Generator is more than just a fun project; it’s a valuable learning experience. It allows you to:

  • Practice API Integration: Fetching data from an external API is a crucial skill for web developers.
  • Master State Management: Learn how to manage and update the application’s state.
  • Understand Component-Based Architecture: Build reusable and modular UI components.
  • Explore Dynamic Rendering: Display different quotes each time the app loads or a button is clicked.

This project is perfect for beginners and intermediate developers looking to solidify their understanding of Next.js and web development principles. It’s a stepping stone to building more complex applications.

Prerequisites

Before we begin, ensure you have the following installed on your system:

  • Node.js and npm (or yarn): This is the foundation for running JavaScript on your server and managing project dependencies.
  • A code editor: Visual Studio Code, Sublime Text, or any editor you prefer.
  • Basic understanding of HTML, CSS, and JavaScript: Familiarity with these languages is essential.

Step-by-Step Guide

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 random-quote-generator

This command creates a new directory called `random-quote-generator` with the basic structure for a Next.js application. Navigate into the project directory:

cd random-quote-generator

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.

2. Project Structure and File Setup

Let’s organize our project. We’ll primarily work within the `pages` directory. Create a new file called `index.js` inside the `pages` directory. This will be the main page of our application. Also, create a `components` folder at the root of your project directory to house our reusable components.

Your project structure should look like this:

random-quote-generator/
├── node_modules/
├── pages/
│   └── index.js
├── components/
├── public/
├── .gitignore
├── package.json
├── README.md
└── ...

3. Creating the Quote Component

Inside the `components` folder, create a new file named `Quote.js`. This component will be responsible for displaying the quote and the author.

// components/Quote.js
import React from 'react';

function Quote({ quote, author }) {
  return (
    <div>
      <p>"{quote}"</p>
      <p>- {author}</p>
    </div>
  );
}

export default Quote;

This component takes `quote` and `author` as props and renders them inside a simple HTML structure. This is a functional component; it’s a simple function that returns JSX (JavaScript XML) to describe the UI.

4. Fetching Quotes from an API

We’ll use a free API to fetch random quotes. There are several options available; for this tutorial, we will use Quotable API. This API provides a simple endpoint to get a random quote. Let’s create a function to fetch the quote.

Inside `pages/index.js`, import `useState` and `useEffect` from `react`:

import React, { useState, useEffect } from 'react';
import Quote from '../components/Quote'; // Import the Quote component

Then, define a state variable to hold the quote data and the function to fetch the quote:

function HomePage() {
  const [quoteData, setQuoteData] = useState({ quote: '', author: '' });
  const [isLoading, setIsLoading] = useState(true);
  const [error, setError] = useState(null);

  useEffect(() => {
    const fetchQuote = async () => {
      setIsLoading(true);
      setError(null);
      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();
        setQuoteData({ quote: data.content, author: data.author });
      } catch (err) {
        setError(err.message);
      } finally {
        setIsLoading(false);
      }
    };

    fetchQuote();
  }, []); // The empty dependency array ensures this effect runs only once, on component mount.

  // ... rest of the component
}

Let’s break down this code:

  • useState: We use `useState` to manage three states: quoteData to store the quote and author, isLoading to indicate whether the data is being fetched, and error to handle potential errors during the API call.
  • useEffect: The `useEffect` hook runs the `fetchQuote` function after the component mounts. The empty dependency array `[]` ensures that this effect runs only once, similar to `componentDidMount` in class components.
  • fetchQuote: This asynchronous function uses the `fetch` API to retrieve a quote from the Quotable API. It handles potential errors using a `try…catch…finally` block. It updates the state with the fetched quote data or error messages.

5. Displaying the Quote in index.js

Now, let’s render the fetched quote within the `index.js` file. Modify the `HomePage` component in `pages/index.js` to include the `Quote` component and display the data.

// pages/index.js
import React, { useState, useEffect } from 'react';
import Quote from '../components/Quote';

function HomePage() {
  const [quoteData, setQuoteData] = useState({ quote: '', author: '' });
  const [isLoading, setIsLoading] = useState(true);
  const [error, setError] = useState(null);

  useEffect(() => {
    const fetchQuote = async () => {
      setIsLoading(true);
      setError(null);
      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();
        setQuoteData({ quote: data.content, author: data.author });
      } catch (err) {
        setError(err.message);
      } finally {
        setIsLoading(false);
      }
    };

    fetchQuote();
  }, []);

  return (
    <div>
      <h1>Random Quote Generator</h1>
      {isLoading && <p>Loading quote...</p>}
      {error && <p>Error: {error}</p>}
      {!isLoading && !error && (
        
      )}
    </div>
  );
}

export default HomePage;

Here’s what changed:

  • Conditional Rendering: We use conditional rendering to display different content based on the `isLoading` and `error` states. If `isLoading` is true, we display “Loading quote…”. If there is an `error`, we show the error message. If neither `isLoading` nor `error` are present, then the Quote component is rendered.
  • Passing Props: We pass the `quote` and `author` data from the `quoteData` state as props to the `Quote` component.

6. Adding a Button to Get a New Quote

Let’s add a button that allows the user to fetch a new quote on demand. Modify the `index.js` to include a button and a function to fetch a new quote when the button is clicked:

// pages/index.js
import React, { useState, useEffect } from 'react';
import Quote from '../components/Quote';

function HomePage() {
  const [quoteData, setQuoteData] = useState({ quote: '', author: '' });
  const [isLoading, setIsLoading] = useState(true);
  const [error, setError] = useState(null);

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

  const fetchQuote = async () => {
    setIsLoading(true);
    setError(null);
    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();
      setQuoteData({ quote: data.content, author: data.author });
    } catch (err) {
      setError(err.message);
    } finally {
      setIsLoading(false);
    }
  };

  return (
    <div>
      <h1>Random Quote Generator</h1>
      {isLoading && <p>Loading quote...</p>}
      {error && <p>Error: {error}</p>}
      {!isLoading && !error && (
        
      )}
      <button>New Quote</button>
    </div>
  );
}

export default HomePage;

Here, we added a `fetchQuote` function and called it both within `useEffect` (on component mount) and when the button is clicked. This allows you to get a new quote whenever you want.

7. Styling the Application (Optional)

Let’s add some basic styling to make our quote generator look nicer. Create a `styles` directory at the root of your project and create a file called `Quote.module.css` (or any name you prefer). Add the following CSS:

/* styles/Quote.module.css */
div {
  font-family: sans-serif;
  text-align: center;
  margin: 20px;
  padding: 20px;
  border: 1px solid #ccc;
  border-radius: 8px;
  background-color: #f9f9f9;
}

p {
  margin: 10px 0;
  font-size: 1.2em;
}

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

Now, import this CSS file into your `Quote.js` component:

// components/Quote.js
import React from 'react';
import styles from '../styles/Quote.module.css';

function Quote({ quote, author }) {
  return (
    <div>
      <p>"{quote}"</p>
      <p>- {author}</p>
    </div>
  );
}

export default Quote;

Note: Remember to add the corresponding class names to the HTML elements within the Quote component to apply the styles. In this example, we’ve used `styles.container`, `styles.quote`, and `styles.author`.

You can customize the CSS to your liking to improve the look and feel of the quote generator.

8. Deploying Your Application

Once you’ve built your application, you’ll likely want to share it with the world. Next.js makes deployment easy. You can deploy your Next.js app to various platforms, including Vercel (which is recommended for Next.js apps), Netlify, or other hosting providers.

For Vercel deployment:

  1. Sign up for a Vercel account: If you don’t already have one, create an account at Vercel.
  2. Connect your Git repository: Import your project from GitHub, GitLab, or Bitbucket.
  3. Deploy: Vercel will automatically detect your Next.js project and deploy it.

Vercel provides a seamless deployment experience, automatically handling build processes and serverless functions.

Common Mistakes and Troubleshooting

  • CORS Errors: If you encounter CORS (Cross-Origin Resource Sharing) errors when fetching data from the API, ensure that the API supports CORS or consider using a proxy server.
  • Incorrect API Endpoint: Double-check the API endpoint URL to ensure it’s correct.
  • Typographical Errors: Carefully review your code for typos, especially in variable names and component names.
  • Dependency Issues: Make sure you have installed all necessary dependencies using `npm install` or `yarn install`.
  • State Updates: When updating state, ensure that you are using the correct `setQuoteData` function to update the `quoteData` state.

Summary / Key Takeaways

This tutorial demonstrated how to build a Random Quote Generator using Next.js. You learned about:

  • Setting up a Next.js project.
  • Creating and using components.
  • Fetching data from an external API using `fetch`.
  • Managing state with `useState`.
  • Handling side effects with `useEffect`.
  • Conditional rendering in React.
  • Basic styling with CSS modules.

This project provides a solid foundation for building more complex applications in Next.js. You can expand this project by adding features such as:

  • Quote Categories: Allow users to select quote categories (e.g., motivational, funny).
  • Quote Saving: Implement a feature to save favorite quotes.
  • User Authentication: Integrate user authentication for personalized experiences.
  • More Styling: Improve the user interface with more CSS.

FAQ

  1. How can I change the API used for quotes?

    You can easily switch the API by changing the API endpoint URL in the `fetch` function within the `fetchQuote` function in `pages/index.js`.

  2. How do I add more styling?

    You can add more styling by modifying the CSS file (e.g., `Quote.module.css`) or by using a CSS-in-JS solution like Styled Components.

  3. Can I use this project as a starting point for a larger application?

    Yes, absolutely! This project is a great foundation. You can add features like user accounts, quote categories, and more to create a more robust application.

  4. Why am I getting CORS errors?

    CORS errors occur when the API you’re fetching data from doesn’t allow requests from your domain. You can try using a proxy server or, if the API supports it, configuring CORS on the server-side. Sometimes, using a different API that already allows CORS might be a quick solution.

Building this Random Quote Generator is a rewarding experience. As you delve deeper into web development, remember that practice is key. Experiment with different features, explore new APIs, and continually refine your skills. Every project you undertake brings you closer to mastering the art of building interactive and engaging web applications. The knowledge and experience gained from this small project will undoubtedly aid you in more complex coding endeavors in the future.