1. Prima di iniziare
In questo codelab, imparerai a integrare Firebase con un'app web Next.js chiamata friendly Eats, un sito web per le recensioni di ristoranti.
L'app web completata offre funzionalità utili che dimostrano in che modo Firebase può aiutarti a creare app Next.js. Queste funzionalità includono:
- Compilazione ed esecuzione automatica: questo codelab utilizza Firebase App Hosting per compilare ed eseguire automaticamente il codice Next.js ogni volta che esegui il push in un ramo configurato.
- Accesso e disconnessione:l'app web completata ti consente di accedere con Google e uscire. L'accesso e la persistenza degli utenti sono gestiti interamente tramite Firebase Authentication.
- Immagini: l'app web completata consente agli utenti che hanno eseguito l'accesso di caricare le immagini dei ristoranti. Gli asset immagine vengono archiviati in Cloud Storage for Firebase. L'SDK Firebase JavaScript fornisce un URL pubblico alle immagini caricate. Questo URL pubblico viene poi archiviato nel documento del ristorante pertinente in Cloud Firestore.
- Recensioni: l'app web completata consente agli utenti che hanno eseguito l'accesso di pubblicare recensioni dei ristoranti costituite da una valutazione a stelle e da un messaggio di testo. Le informazioni sulle recensioni vengono archiviate in Cloud Firestore.
- Filtri:l'app web completata consente agli utenti che hanno eseguito l'accesso di filtrare l'elenco dei ristoranti in base a categoria, posizione e prezzo. Puoi anche personalizzare il metodo di ordinamento utilizzato. I dati vengono acceduti da Cloud Firestore e le query di Firestore vengono applicate in base ai filtri utilizzati.
Prerequisiti
- Un account GitHub
- Conoscenza di Next.js e JavaScript
Obiettivi didattici
- Come utilizzare Firebase con il router per le app Next.js e il rendering lato server.
- Come mantenere le immagini in Cloud Storage for Firebase.
- Come leggere e scrivere dati in un database Cloud Firestore.
- Come utilizzare Accedi con Google con l'SDK Firebase JavaScript.
Che cosa ti serve
- Git
- Una versione stabile recente di Node.js
- Un browser a tua scelta, ad esempio Google Chrome.
- Un ambiente di sviluppo con un editor di codice e un terminale
- Un Account Google per la creazione e la gestione del tuo progetto Firebase
- La possibilità di eseguire l'upgrade del progetto Firebase al piano tariffario Blaze
2. Configura l'ambiente di sviluppo e il repository GitHub
Questo codelab fornisce il codice di base dell'app e si basa sull'interfaccia a riga di comando di Firebase.
Crea un repository GitHub
Il codice sorgente del codelab è disponibile all'indirizzo https://github.com/firebase/friendlyeats-web. Il repository contiene progetti di esempio per più piattaforme. Tuttavia, questo codelab utilizza solo la directory nextjs-start
. Prendi nota delle seguenti directory:
* `nextjs-start`: contains the starter code upon which you build.
* `nextjs-end`: contains the solution code for the finished web app.
Copia la cartella nextjs-start
nel tuo repository:
- Utilizzando un terminale, crea una nuova cartella sul computer e passa alla nuova directory:
mkdir codelab-friendlyeats-web cd codelab-friendlyeats-web
- Utilizza il pacchetto npm giget per recuperare solo la cartella
nextjs-start
:npx giget@latest gh:firebase/friendlyeats-web/nextjs-start#master . --install
- Monitora le modifiche localmente con Git:
git init git commit -a -m "codelab starting point" git branch -M main
- Crea un nuovo repository GitHub: https://github.com/new. Assegna un nome a piacere.
- GitHub ti fornirà un nuovo URL del repository simile a
https://github.com/
o/ .git git@github.com:
. Copia questo URL./ .git
- GitHub ti fornirà un nuovo URL del repository simile a
- Esegui il push delle modifiche locali al tuo nuovo repository GitHub. Esegui questo comando, sostituendo l'URL del tuo repository con il segnaposto
.git remote add origin <your-repository-url> git push -u origin main
- Ora dovresti vedere il codice di avvio nel tuo repository GitHub.
Installa o aggiorna l'interfaccia a riga di comando di Firebase
Esegui il seguente comando per verificare di avere installato l'interfaccia a riga di comando di Firebase e che sia la versione 13.9.0 o successiva:
firebase --version
Se vedi una versione precedente o non hai installato Firebase CLI, esegui il comando di installazione:
npm install -g firebase-tools@latest
Se non riesci a installare l'interfaccia a riga di comando di Firebase a causa di errori di autorizzazione, consulta la documentazione di npm o utilizza un'altra opzione di installazione.
Accedi a Firebase
- Esegui questo comando per accedere all'interfaccia a riga di comando di Firebase:
firebase login
- A seconda che tu voglia che Firebase raccolga i dati, inserisci
Y
oN
. - Nel browser, seleziona il tuo Account Google e fai clic su Consenti.
3. Configura il progetto Firebase
In questa sezione, configurerai un progetto Firebase e ne associerai un'app web Firebase. Inoltre, configurerai i servizi Firebase utilizzati dall'app web di esempio.
Crea un progetto Firebase
- Nella console Firebase, fai clic su Aggiungi progetto.
- Nella casella di testo Inserisci il nome del progetto, inserisci
FriendlyEats Codelab
(o il nome del progetto che preferisci) e fai clic su Continua. - Nella finestra modale Conferma piano di fatturazione Firebase, verifica che il piano sia Blaze e poi fai clic su Conferma piano.
- Per questo codelab, non hai bisogno di Google Analytics, quindi disattiva l'opzione Abilita Google Analytics per questo progetto.
- Fai clic su Crea progetto.
- Attendi il provisioning del progetto, poi fai clic su Continua.
- Nel progetto Firebase, vai a Impostazioni progetto. Prendi nota dell'ID progetto perché ti servirà in un secondo momento. Questo identificatore univoco è il modo in cui viene identificato il progetto (ad esempio, nell'interfaccia a riga di comando di Firebase).
Esegui l'upgrade del piano tariffario Firebase
Per utilizzare Firebase App Hosting e Cloud Storage for Firebase, il tuo progetto Firebase deve utilizzare il piano tariffario con pagamento a consumo (Blaze), il che significa che deve essere collegato a un account di fatturazione Cloud.
- Un account di fatturazione Cloud richiede un metodo di pagamento, ad esempio una carta di credito.
- Se non hai mai utilizzato Firebase e Google Cloud, controlla se hai l'idoneità a ricevere un credito di 300 $ e un account di fatturazione Cloud per la prova gratuita.
- Se stai svolgendo questo codelab nell'ambito di un evento, chiedi all'organizzatore se sono disponibili crediti Cloud.
Per eseguire l'upgrade del progetto al piano Blaze, segui questi passaggi:
- Nella console Firebase, scegli di eseguire l'upgrade del piano.
- Seleziona il piano Blaze. Segui le istruzioni sullo schermo per collegare un account di fatturazione Cloud al tuo progetto.
Se hai dovuto creare un account di fatturazione Cloud nell'ambito di questo upgrade, potresti dover tornare al flusso di upgrade nella console Firebase per completarlo.
Aggiungi un'app web al progetto Firebase
- Vai alla Panoramica del progetto nel progetto Firebase e fai clic su Web.
Se nel progetto hai già registrato delle app, fai clic su Aggiungi app per visualizzare l'icona Web. - Nella casella di testo Nickname app, inserisci un nickname per l'app facile da ricordare, ad esempio
My Next.js app
. - Lascia deselezionata la casella di controllo Configura anche Firebase Hosting per questa app.
- Fai clic su Registra app > Avanti > Avanti > Vai alla console.
Configurare i servizi Firebase nella console Firebase
Configura l'autenticazione
- Nella Console Firebase, vai ad Autenticazione.
- Fai clic su Inizia.
- Nella colonna Fornitori aggiuntivi, fai clic su Google > Attiva.
- Nella casella di testo Nome visibile al pubblico del progetto, inserisci un nome facile da ricordare, ad esempio
My Next.js app
. - Nel menu a discesa Email dell'assistenza per il progetto, seleziona il tuo indirizzo email.
- Fai clic su Salva.
Configura Cloud Firestore
- Nel riquadro a sinistra della console Firebase, espandi Crea e seleziona Database Firestore.
- Fai clic su Crea database.
- Lascia il campo ID database impostato su
(default)
. - Seleziona una posizione per il database, poi fai clic su Avanti.
Per un'app reale, devi scegliere una località vicina agli utenti. - Fai clic su Avvia in modalità di test. Leggi il disclaimer relativo alle regole di sicurezza.
Più avanti in questo codelab aggiungerai le regole di sicurezza per proteggere i tuoi dati. Non distribuire o esporre pubblicamente un'app senza aggiungere regole di sicurezza per il tuo database. - Fai clic su Crea.
Configura Cloud Storage per Firebase
- Nel riquadro a sinistra della console Firebase, espandi Crea e seleziona Spazio di archiviazione.
- Fai clic su Inizia.
- Seleziona una località per il bucket di archiviazione predefinito.
I bucket inUS-WEST1
,US-CENTRAL1
eUS-EAST1
possono sfruttare il livello "Sempre senza costi" per Google Cloud Storage. I bucket in tutte le altre località seguono i prezzi e l'utilizzo di Google Cloud Storage. - Fai clic su Avvia in modalità di test. Leggi il disclaimer relativo alle regole di sicurezza.
Più avanti in questo codelab, aggiungerai regole di sicurezza per proteggere i tuoi dati. Non distribuire o esporre pubblicamente un'app senza aggiungere regole di sicurezza per il bucket Storage. - Fai clic su Crea.
4. Esamina il codice di base di avvio
In questa sezione esaminerai alcune aree della base di codice di avvio dell'app a cui aggiungerai funzionalità in questo codelab.
Struttura di cartelle e file
La tabella seguente contiene una panoramica della struttura di file e cartelle dell'app:
Cartelle e file | Descrizione |
| Componenti React per filtri, intestazioni, dettagli del ristorante e recensioni |
| Funzioni di utilità che non sono necessariamente associate a React o Next.js |
| Codice e configurazione Firebase specifici |
| Asset statici nell'app web, come le icone |
| Routing con il router dell'app Next.js |
| Un gestore di route API |
| Dipendenze del progetto con npm |
| Configurazione specifica di Next.js (le azioni del server sono attivate) |
| Configurazione del servizio di linguaggio JavaScript |
Componenti server e client
L'app è un'app web Next.js che utilizza App Router. Il rendering lato server viene utilizzato in tutta l'app. Ad esempio, il file src/app/page.js
è un componente del server responsabile della pagina principale. Il file src/components/RestaurantListings.jsx
è un componente client indicato dall'istruzione "use client"
all'inizio del file.
Importa estratti conto
Potresti notare dichiarazioni di importazione come la seguente:
import RatingPicker from "@/src/components/RatingPicker.jsx";
L'app utilizza il simbolo @
per evitare percorsi di importazione relativi incomprensibili ed è possibile grazie agli alias del percorso.
API specifiche di Firebase
Tutto il codice dell'API Firebase è racchiuso nella directory src/lib/firebase
. I singoli componenti di React importano quindi le funzioni con wrapping dalla directory src/lib/firebase
, anziché importare direttamente le funzioni Firebase.
Dati fittizi
I dati fittizi relativi a ristoranti e recensioni sono contenuti nel file src/lib/randomData.js
. I dati di questo file vengono assemblati nel codice del file src/lib/fakeRestaurants.js
.
5. Crea un backend di hosting delle app
In questa sezione configurerai un backend App Hosting per monitorare un ramo nel tuo repository Git.
Al termine di questa sezione, avrai un backend di App Hosting collegato al tuo repository su GitHub che eseguirà automaticamente la nuova compilazione e il deployment di una nuova versione della tua app ogni volta che esegui il push di un nuovo commit nel ramo main
.
Esegui il deployment delle regole di sicurezza
Il codice include già insiemi di regole di sicurezza per Firestore e per Cloud Storage for Firebase. Dopo aver implementato le regole di sicurezza, i dati nel database e nel bucket sono protetti meglio da usi impropri.
- Nel terminale, configura l'interfaccia a riga di comando in modo da utilizzare il progetto Firebase creato in precedenza:
Quando viene richiesto un alias, inseriscifirebase use --add
friendlyeats-codelab
. - Per eseguire il deployment di queste regole di sicurezza, esegui questo comando nel tuo terminale:
firebase deploy --only firestore:rules,storage
- Se ti viene chiesto:
"Cloud Storage for Firebase needs an IAM Role to use cross-service rules. Grant the new role?"
, premiEnter
per selezionare Sì.
Aggiungi la configurazione di Firebase al codice dell'app web
- Nella Console Firebase, vai alle Impostazioni progetto.
- Nel riquadro Configurazione e installazione dell'SDK, fai clic su "Aggiungi app" e poi sull'icona delle parentesi graffe del codice
per registrare una nuova app web.
- Al termine del flusso di creazione dell'app web, copia la variabile
firebaseConfig
, quindi copia le relative proprietà e i relativi valori. - Apri il file
apphosting.yaml
nell'editor di codice e compila i valori delle variabili di ambiente con i valori di configurazione della Console Firebase. - Nel file, sostituisci le proprietà esistenti con quelle che hai copiato.
- Salva il file.
Crea un backend
- Accedi alla pagina App Hosting nella Console Firebase:
- Fai clic su "Inizia" per avviare il flusso di creazione del backend. Configura il backend come segue:
- Segui le istruzioni nel primo passaggio per connettere il repository GitHub che hai creato in precedenza.
- Imposta le impostazioni di deployment:
- Mantieni la directory principale come
/
- Imposta il ramo attivo su
main
- Abilita implementazioni automatiche
- Mantieni la directory principale come
- Assegna un nome al backend
friendlyeats-codelab
. - In "Crea o associa un'app web Firebase", scegli l'app web configurata in precedenza dal menu a discesa "Seleziona un'app web Firebase esistente".
- Fai clic su "Termina ed esegui il deployment". Dopo un istante, verrà visualizzata una nuova pagina in cui potrai vedere lo stato del nuovo backend di App Hosting.
- Una volta completata l'implementazione, fai clic sul tuo dominio senza costi in "domini". Questa operazione potrebbe richiedere alcuni minuti per iniziare a funzionare a causa della propagazione del DNS.
Hai eseguito il deployment dell'app web iniziale. Ogni volta che esegui il push di un nuovo commit nel ramo main
del tuo repository GitHub, nella Console Firebase viene avviata una nuova build e un nuovo rollout e il tuo sito verrà aggiornato automaticamente al termine dell'implementazione.
6. Aggiungere l'autenticazione all'app web
In questa sezione, aggiungerai l'autenticazione all'app web per potervi accedere.
Implementa le funzioni di accesso e disconnessione
- Nel file
src/lib/firebase/auth.js
, sostituisci le funzionionAuthStateChanged
,signInWithGoogle
esignOut
con il seguente codice:
export function onAuthStateChanged(cb) {
return _onAuthStateChanged(auth, cb);
}
export async function signInWithGoogle() {
const provider = new GoogleAuthProvider();
try {
await signInWithPopup(auth, provider);
} catch (error) {
console.error("Error signing in with Google", error);
}
}
export async function signOut() {
try {
return auth.signOut();
} catch (error) {
console.error("Error signing out with Google", error);
}
}
Questo codice utilizza le seguenti API Firebase:
API Firebase | Descrizione |
Crea un'istanza del provider di autenticazione Google. | |
Avvia un flusso di autenticazione basato su dialogo. | |
L'utente viene disconnesso. |
Nel file src/components/Header.jsx
, il codice richiama già le funzioni signInWithGoogle
e signOut
.
- Crea un commit con il messaggio "Aggiunta dell'autenticazione Google" ed esegui il push nel tuo repository GitHub. 1. Apri la pagina App Hosting nella Console Firebase e attendi il completamento della nuova implementazione.
- Nell'app web, aggiorna la pagina e fai clic su Accedi con Google. L'app web non si aggiorna, quindi non è chiaro se l'accesso è riuscito.
Invia lo stato dell'autenticazione al server
Per passare lo stato dell'autenticazione al server, utilizzeremo un service worker. Sostituisci le funzioni fetchWithFirebaseHeaders
e getAuthIdToken
con il seguente codice:
async function fetchWithFirebaseHeaders(request) {
const app = initializeApp(firebaseConfig);
const auth = getAuth(app);
const installations = getInstallations(app);
const headers = new Headers(request.headers);
const [authIdToken, installationToken] = await Promise.all([
getAuthIdToken(auth),
getToken(installations),
]);
headers.append("Firebase-Instance-ID-Token", installationToken);
if (authIdToken) headers.append("Authorization", `Bearer ${authIdToken}`);
const newRequest = new Request(request, { headers });
return await fetch(newRequest);
}
async function getAuthIdToken(auth) {
await auth.authStateReady();
if (!auth.currentUser) return;
return await getIdToken(auth.currentUser);
}
Leggi lo stato di autenticazione sul server
Utilizzeremo FirebaseServerApp per eseguire il mirroring dello stato dell'autenticazione del client sul server.
Apri src/lib/firebase/serverApp.js
e sostituisci la funzione getAuthenticatedAppForUser
:
export async function getAuthenticatedAppForUser() {
const idToken = headers().get("Authorization")?.split("Bearer ")[1];
console.log('firebaseConfig', JSON.stringify(firebaseConfig));
const firebaseServerApp = initializeServerApp(
firebaseConfig,
idToken
? {
authIdToken: idToken,
}
: {}
);
const auth = getAuth(firebaseServerApp);
await auth.authStateReady();
return { firebaseServerApp, currentUser: auth.currentUser };
}
Iscriversi alle modifiche all'autenticazione
Per iscriverti alle modifiche di autenticazione, segui questi passaggi:
- Vai al file
src/components/Header.jsx
. - Sostituisci la funzione
useUserSession
con il seguente codice:
function useUserSession(initialUser) {
// The initialUser comes from the server via a server component
const [user, setUser] = useState(initialUser);
const router = useRouter();
// Register the service worker that sends auth state back to server
// The service worker is built with npm run build-service-worker
useEffect(() => {
if ("serviceWorker" in navigator) {
const serializedFirebaseConfig = encodeURIComponent(JSON.stringify(firebaseConfig));
const serviceWorkerUrl = `/auth-service-worker.js?firebaseConfig=${serializedFirebaseConfig}`
navigator.serviceWorker
.register(serviceWorkerUrl)
.then((registration) => console.log("scope is: ", registration.scope));
}
}, []);
useEffect(() => {
const unsubscribe = onAuthStateChanged((authUser) => {
setUser(authUser)
})
return () => unsubscribe()
// eslint-disable-next-line react-hooks/exhaustive-deps
}, []);
useEffect(() => {
onAuthStateChanged((authUser) => {
if (user === undefined) return
// refresh when user changed to ease testing
if (user?.email !== authUser?.email) {
router.refresh()
}
})
// eslint-disable-next-line react-hooks/exhaustive-deps
}, [user])
return user;
}
Questo codice utilizza un hook stato di reazione per aggiornare l'utente quando la funzione onAuthStateChanged
specifica che è presente una modifica allo stato dell'autenticazione.
Verificare le modifiche
Il layout principale nel file src/app/layout.js
esegue il rendering dell'intestazione e dei passaggi dell'utente, se disponibili, come proposta.
<Header initialUser={currentUser?.toJSON()} />
Ciò significa che il componente <Header>
esegue il rendering dei dati utente, se disponibili, durante il tempo di esecuzione del server. Se durante il ciclo di vita della pagina si verificano aggiornamenti dell'autenticazione dopo il caricamento iniziale della pagina, vengono gestiti dall'handler onAuthStateChanged
.
Ora è il momento di implementare una nuova build e verificare quello che hai creato.
- Crea un commit con il messaggio "Mostra stato accesso" ed esegui il push nel tuo repository GitHub.
- Apri la pagina App Hosting nella Console Firebase e attendi il completamento della nuova implementazione.
- Verifica il nuovo comportamento di autenticazione:
- Nel browser, aggiorna l'app web. Il tuo nome visualizzato appare nell'intestazione.
- Esci e accedi di nuovo. La pagina si aggiorna in tempo reale senza dover aggiornare la pagina. Puoi ripetere questo passaggio con diversi utenti.
- (Facoltativo) Fai clic con il tasto destro del mouse sull'app web, seleziona Visualizza sorgente pagina e cerca il nome visualizzato. Viene visualizzato nel codice sorgente HTML non elaborato restituito dal server.
7. Visualizza informazioni sul ristorante
L'app web include dati fittizi relativi a ristoranti e recensioni.
Aggiungi uno o più ristoranti
Per inserire dati simulati dei ristoranti nel tuo database Cloud Firestore locale:
- Nell'app web, seleziona > Aggiungi ristoranti di esempio.
- Nella console Firebase della pagina Database Firestore, seleziona ristoranti. Nella raccolta dei ristoranti vengono visualizzati i documenti di primo livello, ognuno dei quali rappresenta un ristorante.
- Fai clic su alcuni documenti per esplorare le proprietà di un documento di un ristorante.
Visualizzare l'elenco dei ristoranti
Il tuo database Cloud Firestore ora contiene i ristoranti che l'app web Next.js può mostrare.
Per definire il codice di recupero dati:
- Nel file
src/app/page.js
, individua il componente del server<Home />
e controlla la chiamata alla funzionegetRestaurants
, che recupera un elenco di ristoranti in fase di esecuzione del server. Implementa la funzionegetRestaurants
nei passaggi che seguono. - Nel file
src/lib/firebase/firestore.js
, sostituisci le funzioniapplyQueryFilters
egetRestaurants
con il seguente codice:
function applyQueryFilters(q, { category, city, price, sort }) {
if (category) {
q = query(q, where("category", "==", category));
}
if (city) {
q = query(q, where("city", "==", city));
}
if (price) {
q = query(q, where("price", "==", price.length));
}
if (sort === "Rating" || !sort) {
q = query(q, orderBy("avgRating", "desc"));
} else if (sort === "Review") {
q = query(q, orderBy("numRatings", "desc"));
}
return q;
}
export async function getRestaurants(db = db, filters = {}) {
let q = query(collection(db, "restaurants"));
q = applyQueryFilters(q, filters);
const results = await getDocs(q);
return results.docs.map(doc => {
return {
id: doc.id,
...doc.data(),
// Only plain objects can be passed to Client Components from Server Components
timestamp: doc.data().timestamp.toDate(),
};
});
}
- Crea un commit con il messaggio di commit "Leggi l'elenco dei ristoranti da Firestore" ed eseguine il push nel repository GitHub.
- Apri la pagina App Hosting nella Console Firebase e attendi il completamento della nuova implementazione.
- Nell'app web, aggiorna la pagina. Le immagini dei ristoranti vengono visualizzate come riquadri nella pagina.
Verifica che le schede dei ristoranti vengano caricate in fase di esecuzione del server
Utilizzando il framework Next.js, potrebbe non essere evidente quando i dati vengono caricati in fase di esecuzione del server o lato client.
Per verificare che le schede dei ristoranti vengano caricate in fase di esecuzione del server:
- Nell'app web, apri DevTools e disattiva JavaScript.
- Aggiorna l'app web. Le schede dei ristoranti vengono comunque caricate. Le informazioni sul ristorante vengono restituite nella risposta del server. Quando JavaScript è attivato, le informazioni sul ristorante vengono idratate tramite il codice JavaScript lato client.
- In DevTools, riattiva JavaScript.
Ascolta gli aggiornamenti dei ristoranti con i listener di snapshot di Cloud Firestore
Nella sezione precedente, hai visto come viene caricato l'insieme iniziale di ristoranti dal file src/app/page.js
. Il file src/app/page.js
è un componente del server e viene visualizzato sul server, con il codice di recupero dati di Firebase.
Il file src/components/RestaurantListings.jsx
è un componente client e può essere configurato per eseguire l'hydration del markup eseguito dal server.
Per configurare il file src/components/RestaurantListings.jsx
in modo da eseguire l'idratazione del markup visualizzato dal server:
- Nel file
src/components/RestaurantListings.jsx
osserva il seguente codice, che è già stato scritto automaticamente:
useEffect(() => {
const unsubscribe = getRestaurantsSnapshot(data => {
setRestaurants(data);
}, filters);
return () => {
unsubscribe();
};
}, [filters]);
Questo codice richiama la funzione getRestaurantsSnapshot()
, simile alla funzione getRestaurants()
implementata in un passaggio precedente. Tuttavia, questa funzione di snapshot fornisce un meccanismo di callback in modo che venga richiamato ogni volta che viene apportata una modifica alla raccolta del ristorante.
- Nel file
src/lib/firebase/firestore.js
, sostituisci la funzionegetRestaurantsSnapshot()
con il seguente codice:
export function getRestaurantsSnapshot(cb, filters = {}) {
if (typeof cb !== "function") {
console.log("Error: The callback parameter is not a function");
return;
}
let q = query(collection(db, "restaurants"));
q = applyQueryFilters(q, filters);
const unsubscribe = onSnapshot(q, querySnapshot => {
const results = querySnapshot.docs.map(doc => {
return {
id: doc.id,
...doc.data(),
// Only plain objects can be passed to Client Components from Server Components
timestamp: doc.data().timestamp.toDate(),
};
});
cb(results);
});
return unsubscribe;
}
Le modifiche apportate tramite la pagina Database Firestore ora si riflettono nell'app web in tempo reale.
- Crea un commit con il messaggio "Ascolta gli aggiornamenti in tempo reale dei ristoranti" ed esegui il push nel tuo repository GitHub.
- Apri la pagina Hosting app nella Console Firebase e attendi il completamento del nuovo implementazione.
- Nell'app web, seleziona > Aggiungi ristoranti di esempio. Se la funzione di istantanea è implementata correttamente, i ristoranti vengono visualizzati in tempo reale senza aggiornare la pagina.
8. Salvare le recensioni inviate dagli utenti dall'app web
- Nel file
src/lib/firebase/firestore.js
, sostituisci la funzioneupdateWithRating()
con il seguente codice:
const updateWithRating = async (
transaction,
docRef,
newRatingDocument,
review
) => {
const restaurant = await transaction.get(docRef);
const data = restaurant.data();
const newNumRatings = data?.numRatings ? data.numRatings + 1 : 1;
const newSumRating = (data?.sumRating || 0) + Number(review.rating);
const newAverage = newSumRating / newNumRatings;
transaction.update(docRef, {
numRatings: newNumRatings,
sumRating: newSumRating,
avgRating: newAverage,
});
transaction.set(newRatingDocument, {
...review,
timestamp: Timestamp.fromDate(new Date()),
});
};
Questo codice inserisce un nuovo documento Firestore che rappresenta la nuova recensione. Il codice aggiorna anche il documento Firestore esistente che rappresenta il ristorante con i dati aggiornati relativi al numero di valutazioni e alla valutazione media calcolata.
- Sostituisci la funzione
addReviewToRestaurant()
con il seguente codice:
export async function addReviewToRestaurant(db, restaurantId, review) {
if (!restaurantId) {
throw new Error("No restaurant ID has been provided.");
}
if (!review) {
throw new Error("A valid review has not been provided.");
}
try {
const docRef = doc(collection(db, "restaurants"), restaurantId);
const newRatingDocument = doc(
collection(db, `restaurants/${restaurantId}/ratings`)
);
// corrected line
await runTransaction(db, transaction =>
updateWithRating(transaction, docRef, newRatingDocument, review)
);
} catch (error) {
console.error(
"There was an error adding the rating to the restaurant",
error
);
throw error;
}
}
Implementare un'azione del server Next.js
Un'azione del server Next.js fornisce un'API pratica per accedere ai dati del modulo, ad esempio data.get("text")
per ottenere il valore del testo dal payload di invio del modulo.
Per utilizzare un'azione server Next.js per elaborare l'invio del modulo per la revisione:
- Nel file
src/components/ReviewDialog.jsx
, individua l'attributoaction
nell'elemento<form>
.
<form action={handleReviewFormSubmission}>
Il valore dell'attributo action
si riferisce a una funzione che implementi nel passaggio successivo.
- Nel file
src/app/actions.js
, sostituisci la funzionehandleReviewFormSubmission()
con il seguente codice:
// This is a next.js server action, which is an alpha feature, so
// use with caution.
// https://nextjs.org/docs/app/building-your-application/data-fetching/server-actions
export async function handleReviewFormSubmission(data) {
const { app } = await getAuthenticatedAppForUser();
const db = getFirestore(app);
await addReviewToRestaurant(db, data.get("restaurantId"), {
text: data.get("text"),
rating: data.get("rating"),
// This came from a hidden form field.
userId: data.get("userId"),
});
}
Aggiungi recensioni per un ristorante
Hai implementato il supporto per gli invii delle recensioni, quindi ora puoi verificare che le recensioni siano state inserite correttamente in Cloud Firestore.
Per aggiungere una recensione e verificare che sia stata inserita in Cloud Firestore:
- Crea un commit con il messaggio "Consenti agli utenti di inviare recensioni dei ristoranti" ed esegui il push nel tuo repository GitHub.
- Apri la pagina App Hosting nella Console Firebase e attendi il completamento della nuova implementazione.
- Aggiorna l'app web e seleziona un ristorante dalla home page.
- Nella pagina del ristorante, fai clic su .
- Seleziona una valutazione a stelle.
- Scrivi una recensione.
- Fai clic su Invia. La tua recensione viene visualizzata nella parte superiore dell'elenco delle recensioni.
- In Cloud Firestore, cerca il documento del ristorante che hai recensito nel riquadro Aggiungi documento e selezionalo.
- Nel riquadro Avvia raccolta, seleziona valutazioni.
- Nel riquadro Aggiungi documento, trova il documento da esaminare per verificare che sia stato inserito come previsto.
9. Salvare i file caricati dagli utenti dall'app web
In questa sezione aggiungi la funzionalità che ti consente di sostituire l'immagine associata a un ristorante dopo aver eseguito l'accesso. Carica l'immagine in Firebase Storage e aggiorna l'URL dell'immagine nel documento Cloud Firestore che rappresenta il ristorante.
Per salvare i file caricati dagli utenti dall'app web:
- Nel file
src/components/Restaurant.jsx
osserva il codice che viene eseguito quando l'utente carica un file:
async function handleRestaurantImage(target) {
const image = target.files ? target.files[0] : null;
if (!image) {
return;
}
const imageURL = await updateRestaurantImage(id, image);
setRestaurant({ ...restaurant, photo: imageURL });
}
Non sono necessarie modifiche, ma devi implementare il comportamento della funzione updateRestaurantImage()
nei passaggi che seguono.
- Nel file
src/lib/firebase/storage.js
, sostituisci le funzioniupdateRestaurantImage()
euploadImage()
con il seguente codice:
export async function updateRestaurantImage(restaurantId, image) {
try {
if (!restaurantId)
throw new Error("No restaurant ID has been provided.");
if (!image || !image.name)
throw new Error("A valid image has not been provided.");
const publicImageUrl = await uploadImage(restaurantId, image);
await updateRestaurantImageReference(restaurantId, publicImageUrl);
return publicImageUrl;
} catch (error) {
console.error("Error processing request:", error);
}
}
async function uploadImage(restaurantId, image) {
const filePath = `images/${restaurantId}/${image.name}`;
const newImageRef = ref(storage, filePath);
await uploadBytesResumable(newImageRef, image);
return await getDownloadURL(newImageRef);
}
La funzione updateRestaurantImageReference()
è già stata implementata per te. Questa funzione aggiorna il documento di un ristorante esistente in Cloud Firestore con un URL immagine aggiornato.
Verifica la funzionalità di caricamento delle immagini
Per verificare che l'immagine venga caricata come previsto:
- Crea un commit con il messaggio di commit "Consenti agli utenti di modificare la foto di ogni ristorante" ed eseguine il push nel repository GitHub.
- Apri la pagina Hosting app nella Console Firebase e attendi il completamento del nuovo implementazione.
- Nell'app web, verifica di aver eseguito l'accesso e seleziona un ristorante.
- Fai clic su e carica un'immagine dal tuo file system. L'immagine lascia l'ambiente locale e viene caricata in Cloud Storage. L'immagine viene visualizzata subito dopo averla caricata.
- Vai a Cloud Storage for Firebase.
- Vai alla cartella che rappresenta il ristorante. L'immagine che hai caricato esiste nella cartella.
10. Riepilogare le recensioni dei ristoranti con l'AI generativa
In questa sezione aggiungerai una funzionalità di riepilogo delle recensioni, in modo che un utente possa capire rapidamente cosa pensano tutti di un ristorante senza dover leggere ogni recensione.
Memorizzare una chiave API Gemini in Cloud Secret Manager
- Per utilizzare l'API Gemini, devi disporre di una chiave API. Crea una chiave in Google AI Studio.
- Hosting delle app si integra con Cloud Secret Manager per consentirti di archiviare in modo sicuro valori sensibili come le chiavi API:
- In un terminale, esegui il comando per creare un nuovo secret:
firebase apphosting:secrets:set gemini-api-key
- Quando ti viene richiesto il valore del secret, copia e incolla la chiave API Gemini da Google AI Studio.
- Quando ti viene chiesto se il nuovo segreto deve essere aggiunto a
apphosting.yaml
, inserisciY
per accettare.
La chiave API Gemini è ora archiviata in modo sicuro in Cloud Secret Manager ed è accessibile al backend di App Hosting.
Implementare il componente Riepilogo recensioni
- In
src/components/Reviews/ReviewSummary.jsx
, sostituisci la funzioneGeminiSummary
con il seguente codice:export async function GeminiSummary({ restaurantId }) { const { firebaseServerApp } = await getAuthenticatedAppForUser(); const reviews = await getReviewsByRestaurantId( getFirestore(firebaseServerApp), restaurantId ); const genAI = new GoogleGenerativeAI(process.env.GEMINI_API_KEY); const model = genAI.getGenerativeModel({ model: "gemini-pro"}); const reviewSeparator = "@"; const prompt = ` Based on the following restaurant reviews, where each review is separated by a '${reviewSeparator}' character, create a one-sentence summary of what people think of the restaurant. Here are the reviews: ${reviews.map(review => review.text).join(reviewSeparator)} `; try { const result = await model.generateContent(prompt); const response = await result.response; const text = response.text(); return ( <div className="restaurant__review_summary"> <p>{text}</p> <p>✨ Summarized with Gemini</p> </div> ); } catch (e) { console.error(e); return <p>Error contacting Gemini</p>; } }
- Crea un commit con messaggio di commit "Utilizza l'IA per riepilogare le recensioni" ed eseguine il push nel repository GitHub.
- Apri la pagina App Hosting nella Console Firebase e attendi il completamento della nuova implementazione.
- Apri la pagina di un ristorante. In alto, dovresti vedere un riepilogo di una frase di tutte le recensioni nella pagina.
- Aggiungi una nuova recensione e aggiorna la pagina. Dovresti vedere la modifica del riepilogo.
11. Conclusione
Complimenti! Hai imparato a utilizzare Firebase per aggiungere caratteristiche e funzionalità a un'app Next.js. In particolare, hai utilizzato quanto segue:
- Firebase App Hosting per creare e implementare automaticamente il codice Next.js ogni volta che esegui il push a un ramo configurato.
- Firebase Authentication per abilitare le funzionalità di accesso e logout.
- Cloud Firestore per i dati relativi ai ristoranti e alle recensioni dei ristoranti.
- Cloud Storage for Firebase per le immagini dei ristoranti.