Google Books API Integration mit React Bootstrap
In diesem Schritt werden wir die Google Books API in unsere Anwendung integrieren, um echte Buchdaten zu laden und anzuzeigen, und dabei vollständig auf React Bootstrap setzen ohne eigenes CSS.
Ziel dieses Schritts
Abschnitt betitelt „Ziel dieses Schritts“- Die Google Books API verstehen
- API-Aufrufe an Google Books implementieren
- Die Daten der API verarbeiten und anzeigen
- Erweiterte Suchfunktionen hinzufügen
Was ist die Google Books API?
Abschnitt betitelt „Was ist die Google Books API?“Die Google Books API bietet Zugriff auf die umfangreiche Buchsammlung von Google, einschliesslich Metadaten über Bücher wie Titel, Autoren, Beschreibungen und Cover-Bilder.
Google Books API Service erstellen
Abschnitt betitelt „Google Books API Service erstellen“Erstelle eine neue Datei src/services/googleBooksService.js:
// Basis-URL für die Google Books APIconst BASE_URL = "https://www.googleapis.com/books/v1/volumes";
// Funktion zum Abrufen von Büchern basierend auf einem Suchbegriffexport const searchGoogleBooks = async (query, maxResults = 20) => { try { const response = await fetch( `${BASE_URL}?q=${encodeURIComponent(query)}&maxResults=${maxResults}` );
if (!response.ok) { throw new Error(`API Error: ${response.status} ${response.statusText}`); }
const data = await response.json();
// Transformieren der Google Books API Daten in unser Format return data.items ? transformApiResponse(data.items) : []; } catch (error) { console.error("Error fetching from Google Books API:", error); throw error; }};
// Funktion zum Abrufen eines einzelnen Buchs anhand seiner IDexport const getGoogleBookById = async (bookId) => { try { const response = await fetch(`${BASE_URL}/${bookId}`);
if (!response.ok) { throw new Error(`API Error: ${response.status} ${response.statusText}`); }
const data = await response.json();
// Transformieren des einzelnen Buchs in unser Format return transformBookItem(data); } catch (error) { console.error("Error fetching book details:", error); throw error; }};
// Hilfsfunktion zum Transformieren der API-Antwortfunction transformApiResponse(items) { return items.map(transformBookItem).filter((item) => item !== null);}
// Transformiert ein einzelnes Buch-Itemfunction transformBookItem(item) { // Fehlende Buchinformationen abfangen if (!item || !item.volumeInfo) { return null; }
const volumeInfo = item.volumeInfo;
// Extrahieren der Bildinformationen const imageLinks = volumeInfo.imageLinks || {}; const thumbnailUrl = imageLinks.thumbnail || imageLinks.smallThumbnail || null;
return { id: item.id, title: volumeInfo.title || "Unbekannter Titel", author: volumeInfo.authors && volumeInfo.authors.length > 0 ? volumeInfo.authors.join(", ") : "Unbekannter Autor", description: volumeInfo.description || "Keine Beschreibung verfügbar", imageUrl: thumbnailUrl, publishedDate: volumeInfo.publishedDate || "Unbekanntes Datum", pageCount: volumeInfo.pageCount || "Unbekannt", categories: volumeInfo.categories || [], language: volumeInfo.language || "Unbekannt", previewLink: volumeInfo.previewLink || null, };}BookCard Komponente erweitern mit React Bootstrap
Abschnitt betitelt „BookCard Komponente erweitern mit React Bootstrap“import { useState } from "react";import { Card, Button, Badge } from "react-bootstrap";import { FaHeart, FaRegHeart, FaExternalLinkAlt } from "react-icons/fa";
// ÄNDERUNG: Komplett überarbeitet mit React Bootstrap-Komponentenfunction BookCard({ book }) { const { title, author, imageUrl, description, publishedDate, previewLink } = book;
// State für den Favoriten-Status const [isFavorite, setIsFavorite] = useState(false);
// Funktion zum Umschalten des Favoriten-Status const toggleFavorite = () => { setIsFavorite(!isFavorite); };
// Standard-Bild, falls kein Bild-URL bereitgestellt wird const defaultImage = "https://placehold.co/128x192";
return ( <Card className="h-100"> <div className="d-flex flex-column flex-md-row"> <div style={{ flex: "0 0 128px" }}> <Card.Img src={imageUrl || defaultImage} alt={`Cover von ${title}`} style={{ height: "192px", objectFit: "cover" }} /> </div> <Card.Body> <Card.Title>{title}</Card.Title> <Card.Subtitle className="mb-2 text-muted">{author}</Card.Subtitle>
{/* ÄNDERUNG: Veröffentlichungsdatum mit Badge */} {publishedDate && ( <Badge bg="secondary" className="mb-2"> Veröffentlicht: {publishedDate} </Badge> )}
<Card.Text> {description ? description.length > 150 ? `${description.substring(0, 150)}...` : description : "Keine Beschreibung verfügbar"} </Card.Text>
{/* ÄNDERUNG: Aktionsbuttons mit React Icons */} <div className="d-flex gap-2 mt-auto"> {previewLink ? ( <Button variant="primary" href={previewLink} target="_blank" rel="noopener noreferrer" > <FaExternalLinkAlt className="me-1" /> Vorschau </Button> ) : ( <Button variant="primary">Details</Button> )}
<Button variant={isFavorite ? "danger" : "outline-danger"} onClick={toggleFavorite} aria-label={ isFavorite ? "Aus Favoriten entfernen" : "Zu Favoriten hinzufügen" } > {isFavorite ? <FaHeart /> : <FaRegHeart />} </Button> </div> </Card.Body> </div> </Card> );}
export default BookCard;App.jsx mit Google Books API aktualisieren mit React Bootstrap
Abschnitt betitelt „App.jsx mit Google Books API aktualisieren mit React Bootstrap“import { useState, useEffect } from "react";import { Container, Alert, Row, Col } from "react-bootstrap";import Header from "./components/Header/Header";import BookList from "./components/BookList/BookList";import SearchBar from "./components/SearchBar/SearchBar";import LoadingSpinner from "./components/LoadingSpinner/LoadingSpinner";import { searchGoogleBooks } from "./services/googleBooksService";
// ÄNDERUNG: App-Komponente mit React Bootstrapfunction App() { // State für die angezeigten Bücher const [books, setBooks] = useState([]); // State für den Ladezustand const [loading, setLoading] = useState(false); // State für Fehler const [error, setError] = useState(null); // State für den Suchbegriff const [searchTerm, setSearchTerm] = useState(""); // State für initialen Ladezustand const [isInitialLoad, setIsInitialLoad] = useState(true);
// Effekt zum Laden einiger Standardbücher beim Start useEffect(() => { const loadInitialBooks = async () => { try { setLoading(true); // Lade einige populäre Bücher beim Start const initialResults = await searchGoogleBooks("bestseller fiction"); setBooks(initialResults); setError(null); } catch (err) { setError( "Fehler beim Laden der initialen Bücher. Bitte versuche es später erneut." ); console.error("Error loading initial books:", err); } finally { setLoading(false); setIsInitialLoad(false); } };
loadInitialBooks(); }, []); // Leeres Abhängigkeitsarray bedeutet: nur einmal beim Mounten ausführen
// Funktion zum Suchen von Büchern mit der Google Books API const handleSearch = async (term) => { setSearchTerm(term);
if (!term.trim()) { return; // Keine leere Suche ausführen }
try { setLoading(true); setError(null); const results = await searchGoogleBooks(term); setBooks(results); } catch (err) { setError("Fehler bei der Suche. Bitte versuche es später erneut."); console.error("Error searching books:", err); } finally { setLoading(false); } };
return ( <div className="d-flex flex-column min-vh-100"> <Header />
{/* ÄNDERUNG: Layout mit React Bootstrap Container und Spacing */} <Container className="py-4 flex-grow-1"> <Row> <Col> <h2 className="mb-3">Willkommen im Bücher-Projekt</h2> <p className="lead mb-4"> Entdecke neue Bücher und verwalte deine persönliche Büchersammlung. Durchsuche Millionen von Büchern aus der Google Books-Datenbank. </p>
<SearchBar onSearch={handleSearch} />
{error && <Alert variant="danger">{error}</Alert>}
{isInitialLoad ? ( <LoadingSpinner message="Lade empfohlene Bücher..." /> ) : ( <> {searchTerm && !loading && !error && ( <Alert variant="info" className="mt-3"> Ergebnisse für: <strong>{searchTerm}</strong>({books.length}{" "} {books.length === 1 ? "Buch" : "Bücher"} gefunden) </Alert> )}
<h3 className="mt-4 mb-3"> {searchTerm ? "Suchergebnisse" : "Empfohlene Bücher"} </h3> <BookList books={books} loading={loading} /> </> )} </Col> </Row> </Container>
{/* ÄNDERUNG: Footer mit React Bootstrap */} <footer className="bg-light py-3 mt-auto"> <Container className="text-center"> <p className="text-muted mb-0"> © {new Date().getFullYear()} Bücher-Projekt </p> </Container> </footer> </div> );}
export default App;Testen der Google Books API Integration
Abschnitt betitelt „Testen der Google Books API Integration“Starte deine Anwendung:
npm run devJetzt sollten Sie folgendes sehen und testen können:
- Beim Start werden automatisch einige empfohlene Bücher aus der Google Books API geladen
- Sie können nach beliebigen Büchern suchen und die Ergebnisse werden angezeigt
- Jede Buchkarte zeigt Details aus der Google Books API an
- Klick auf den “Vorschau”-Button öffnet die Google Books-Vorschau in einem neuen Tab
Zusammenfassung
Abschnitt betitelt „Zusammenfassung“Die wichtigsten Änderungen in diesem Abschnitt:
- Komplett auf React Bootstrap umgestellt:
- Alle eigenen CSS-Dateien wurden entfernt
- Stattdessen werden React Bootstrap Komponenten verwendet
- Verbesserte UI-Elemente:
- UI mit Bootstrap umgesetzt
- Alerts für Fehlermeldungen und Infos
- Cards für Bücher
- Badges für zusätzliche Informationen
- Grid-System für responsives Layout
- Integration der Google Books API:
- Service für API-Aufrufe
- Transformation der API-Daten
- Behandlung von Erfolgs- und Fehlerfällen
- React Icons für visuelle Elemente:
- Herz-Icons für Favoriten
- Link-Icons für externe Verweise
Diese Implementierung bietet eine saubere, moderne Benutzeroberfläche ohne eigene CSS-Definitionen und nutzt die Stärken von React Bootstrap für ein konsistentes Design.
Danke für Ihr Feedback!