Step-by-Step Implementation of the Project
Step-by-Step Implementation
Now it’s time to build! In this lesson, you’ll walk through setting up the project environment, organizing your files, and writing clean, working code for each part of your app. You’ll see how all the pieces come together, from layout to logic.
Set Up the Environment
Let’s get our development environment ready and create the React app. We will use Create React App (CRA), which is a comfortable environment for learning React and building a new single-page application.
CRA sets up everything we need (Webpack, Babel, development server, etc.) with one command.
1. Install Node.js (if not already installed): As mentioned, ensure Node.js is installed on your system. You can verify by running node -v and npm -v in a terminal; both should output version numbers if installed.
2. Create a new React project: Open your terminal/command prompt, navigate to the folder where you want to create the project, and run:
npx create-react-app quote-generator
This uses npx (which comes with Node) to execute the Create React App tool without installing it globally. Replace “quote-generator” with your desired app name (this will be the project folder name). CRA will scaffold a new React application, installing all the necessary packages. It may take a couple of minutes on first run.
After this command finishes, you will have a new directory called quote-generator (or the name you chose) with the React project files set up.
3. Navigate into the project folder and start the development server:
cd quote-generator
npm start
The npm start script will start the development server. By default, it runs on http://localhost:3000 and opens your browser to that address. You should see the default React welcome page (a spinning React logo and some text) if everything is set up correctly.
At this point, you have a working React app template. The file structure looks something like:
- node_modules/ (all your dependencies, managed by npm)
- public/ (contains the static public assets like the HTML template)
- src/ (your React source code – this is where we will do most of our work)
- package.json (config file listing dependencies and scripts)
We are now ready to modify this template into our Quote Generator app. We’ll mostly be working in the src directory, editing files like App.js, App.css, etc. Next, we’ll examine the structure and then start coding our solution.
Create Application Structure (Directory Structure)
Understanding the project structure generated by Create React App will help you know where to put your code:
quote-generator/
├─ public/
│ ├─ index.html # HTML template (contains <div id="root"></div>)
│ ├─ favicon.ico
│ ├─ manifest.json
│ └─ robots.txt
├─ src/
│ ├─ App.js # Main UI + logic (uses useState/useEffect/useCallback)
│ ├─ App.css # Styles for the app (card, button, layout)
│ ├─ index.js # Entry point: renders <App /> into #root
│ └─ index.css # (Optional) global resets / font imports
├─ .gitignore # Ignores node_modules, build, env files, etc.
├─ package.json # Scripts & dependencies (react, react-scripts)
├─ README.md # Project notes (optional but nice)
└─ (generated on build)
└─ build/ # Production bundle created by `npm run build`
In summary, the App component (App.js) is where we’ll implement the majority of our application (JSX markup and React logic). The index.js will kickstart the App by rendering it into the root DOM node. Our CSS will live in App.css (and possibly a few styles in index.css for global stuff if needed).
Next, we’ll go through the actual implementation steps, modifying these files with code. We’ll provide the code for each file and explain what each part does.
Steps Needed (with file-by-file code and explanation)
Now it’s time to write the code for our Quote Generator app. We’ll go through the important files one by one, showing the code and explaining each piece. The main files to edit are src/index.js, src/App.js, and src/App.css.
1) src/index.js
Open src/index.js and update it as follows (CRA’s template might already be similar):
import React from "react";
import ReactDOM from "react-dom/client";
import App from "./App";
const root = ReactDOM.createRoot(document.getElementById("root"));
root.render(
<React.StrictMode>
<App />
</React.StrictMode>
);Explanation:
- We import React and the ReactDOM client. In React 18+, ReactDOM.createRoot is used for rendering (instead of the older ReactDOM.render). We get the DOM element with id "root" (the one defined in public/index.html) and tell React to render our <App /> component inside it.
- We wrap <App /> in <React.StrictMode> which is a development tool that activates extra checks; it doesn’t affect production output but helps catch potential problems.
- Why we need index.js: This file bootstraps the React application. It is essentially the glue between our React components and the browser DOM. After this, our App component (and its children) control what is displayed on screen.
Now the real work happens in App.js, where we’ll create the Quote Generator logic.
2) src/App.js
Main application component that fetches and displays quotes. Uses DummyJSON as primary and Type.fit as fallback.
import React, { useEffect, useState, useCallback } from "react";
import "./App.css";
export default function App() {
const [quote, setQuote] = useState("");
const [author, setAuthor] = useState("");
const [loading, setLoading] = useState(false);
const [error, setError] = useState("");
const fetchQuote = useCallback(async () => {
setLoading(true);
setError("");
try {
// Primary: DummyJSON
const res = await fetch("https://dummyjson.com/quotes/random");
if (!res.ok) throw new Error(`DummyJSON HTTP ${res.status}`);
const data = await res.json(); // { id, quote, author }
if (!data.quote) throw new Error("DummyJSON returned no quote");
setQuote(data.quote);
setAuthor(data.author || "Unknown");
} catch (e1) {
try {
// Fallback: Type.fit
const r2 = await fetch("https://type.fit/api/quotes");
if (!r2.ok) throw new Error(`Type.fit HTTP ${r2.status}`);
const arr = await r2.json(); // [ { text, author }, ... ]
if (!Array.isArray(arr) || !arr.length)
throw new Error("Type.fit returned empty list");
const q = arr[Math.floor(Math.random() * arr.length)] || {};
setQuote(q.text || "");
setAuthor(q.author || "Unknown");
} catch (e2) {
setQuote("");
setAuthor("");
setError(`Couldn’t load a quote (${e1.message}; ${e2.message}).`);
}
} finally {
setLoading(false);
}
}, []); // stable reference -> safe to put in effect deps
useEffect(() => {
fetchQuote(); // runs once on mount
}, [fetchQuote]);
return (
<div className="App">
<h1>Random Quote Generator</h1>
<div className="quote-box">
{loading ? (
<p className="quote-text">Loading…</p>
) : error ? (
<p className="quote-text">{error}</p>
) : quote ? (
<>
<p className="quote-text">“{quote}”</p>
<p className="quote-author">— {author}</p>
</>
) : (
<p className="quote-text">Click the button for a quote</p>
)}
</div>
<button className="new-quote-button" onClick={fetchQuote} disabled={loading}>
{loading ? "Fetching…" : "New Quote"}
</button>
</div>
);
}Let’s break down what’s happening in this code:
- Imports: We import useState and useEffect from React because we will use these hooks in our component. We also import './App.css' to apply styles (we’ll define those soon).
- State declarations: const [quote, setQuote] = useState('') and const [author, setAuthor] = useState(''). We initialize both quote and author as empty strings. These state variables will hold the current quote’s text and author. Using useState means our component will re-render whenever these values are updated.
- fetchQuote function: This is an async function that encapsulates the logic for retrieving a quote from the Quotable API.
- We call fetch("https://dummyjson.com/quotes/random")to make a GET request to the API. This returns a promise, so we await it.
- const data = await response.json(); – we parse the JSON body of the response. As noted earlier, response.json() returns a promise that resolves with the JS object containing the quote. The object from Quotable will look like: { content: "Quote text", author: "Author Name", _id: "...", tags: [...] }. We only care about content and author fields.
- useEffect hook: We use useEffect to automatically fetch a quote when the component first mounts (when the App component is rendered the first time). The effect callback simply calls fetchQuote() once. We provide an empty dependency array [], which tells React not to re-run this effect on updates – only run it on mount. This means when the app loads, we’ll immediately get one quote from the API and populate the state.
- handleNewQuote: This is the function called when the user clicks the “New Quote” button. It simply calls fetchQuote() again. Since fetchQuote will set state with a new quote, React will re-render and show the new quote. We separate this function mostly for clarity; we could directly pass fetchQuote to onClick, but if we wanted to do more when clicking (like analytics or UI feedback), having a handler is useful.
This App component encapsulates our app’s functionality. To recap the logic: on mount, fetch a quote (via useEffect) -> display quote -> on button click, fetch a new quote -> display new quote. The state and hook usage ensures the UI always reflects the latest quote data.
Now that App.js is set, let’s style the app to make it look presentable.
3) src/App.css (tiny polish)
This is the styling for the app. We’ll add some basic CSS to center the content and make it visually appealing but still simple. Open src/App.css and replace its contents with:
.App {
display: flex;
flex-direction: column;
align-items: center;
justify-content: center;
min-height: 100vh;
background-color: #f0f0f0;
text-align: center;
padding: 20px;
font-family: Arial, sans-serif;
}
h1 {
color: #333;
}
.quote-box {
background-color: #fff;
border-radius: 8px;
padding: 20px 30px;
margin: 20px;
box-shadow: 0 0 10px rgba(0, 0, 0, 0.1);
max-width: 600px;
}
.quote-text {
font-size: 1.5rem;
font-weight: 600;
margin-bottom: 15px;
}
.quote-author {
font-size: 1.2rem;
color: #555;
font-style: italic;
text-align: right;
}
.new-quote-button {
background-color: #007bff;
color: #fff;
border: none;
padding: 12px 24px;
font-size: 1rem;
border-radius: 5px;
cursor: pointer;
margin-top: 10px;
transition: background-color 0.3s;
}
.new-quote-button:hover {
background-color: #0056b3;
}
.quote-text {
min-height: 3.2em;
display: flex;
align-items: center;
justify-content: center;
}
.new-quote-button:disabled {
opacity: 0.75;
cursor: not-allowed;
}These styles should result in a clean and centered UI. The quote will appear in a white box, nicely separated from the background. The button will be below, inviting the user to click for a new quote.
Run the App: If you haven’t already, start the development server with npm start. The app will open at http://localhost:3000. You should see the heading “Random Quote Generator,” and after a moment (while it fetches the first quote) you’ll see a quote displayed. There will be a “New Quote” button. Try clicking it – the text should update to a new quote each time (with a new author if applicable). Congratulations, you have a working quote generator!











