1. Prima di iniziare
In questo codelab imparerai a integrare Firebase con un'app web Next.js chiamata Friendly Eats, un sito web di recensioni di ristoranti.
L'app web completata offre funzionalità utili che dimostrano come 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 uscita: l'app web completata ti consente di accedere con Google e di 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 del ristorante. 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, località 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 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.
Creare 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 nel nuovo repository GitHub. Esegui il comando seguente sostituendo l'URL del tuo repository al 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 il seguente 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. Configura anche 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 è necessario 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 seguito. Questo identificatore univoco serve a identificare il progetto (ad esempio nella CLI di Firebase).
Eseguire l'upgrade del piano tariffario di Firebase
Per utilizzare Firebase App Hosting e Cloud Storage for Firebase, il tuo progetto Firebase deve utilizzare il piano tariffario Blaze con pagamento a consumo, 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 senza costi.
- 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:
- Nella console Firebase, seleziona 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.
Aggiungere un'app web al progetto Firebase
- Vai a Panoramica del progetto nel tuo progetto Firebase, poi fai clic su Web.
Se hai già registrato app nel tuo progetto, 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
. - Mantieni 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
Configurare 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 Build e seleziona Database Firestore.
- Fai clic su Crea database.
- Lascia l'ID database impostato su
(default)
. - Seleziona una posizione per il database, poi fai clic su Avanti.
Per un'app reale, scegli una posizione vicina ai tuoi 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.
Configurare Cloud Storage for Firebase
- Nel riquadro a sinistra della console Firebase, espandi Build e seleziona Archiviazione.
- Fai clic su Inizia.
- Seleziona una posizione per il bucket di archiviazione predefinito.
I bucket inUS-WEST1
,US-CENTRAL1
eUS-EAST1
possono usufruire del livello"Sempre senza costi" per Google Cloud Storage. I bucket in tutte le altre località rispettano 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 un'app pubblicamente senza aggiungere regole di sicurezza per il bucket di archiviazione. - 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à non necessariamente legate 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 linguistico 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 dalla direttiva "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 complicati ed è resa possibile dagli alias di percorso.
API specifiche di Firebase
Tutto il codice dell'API Firebase è racchiuso nella directory src/lib/firebase
. I singoli componenti React importano quindi le funzioni con wrapping dalla directory src/lib/firebase
, anziché importare direttamente le funzioni Firebase.
Dati simulati
I dati del ristorante e delle recensioni simulati 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 ricostruirà e implementerà automaticamente 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 contiene già insiemi di regole di sicurezza per Firestore e 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:
firebase use --add
Quando ti viene richiesto un alias, inseriscifriendlyeats-codelab
. - Per eseguire il deployment di queste regole di sicurezza, esegui questo comando nel 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 impostazione 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
e 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
- Vai alla pagina Hosting app 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 collegare il repository GitHub 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 che hai configurato in precedenza dal menu a discesa "Seleziona un'app web Firebase esistente".
- Fai clic su "Fine ed esegui il deployment". Dopo un istante, verrà visualizzata una nuova pagina in cui potrai vedere lo stato del nuovo backend di App Hosting.
- Al termine dell'implementazione, fai clic sul tuo dominio senza costi in "domini". L'inizio del funzionamento potrebbe richiedere alcuni minuti 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 aggiungi 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 Hosting app nella Console Firebase e attendi il completamento del nuovo 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 è andato a buon fine.
Invia lo stato di autenticazione al server
Per passare lo stato di 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 rispecchiare lo stato di 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 all'autenticazione:
- 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 state di React per aggiornare l'utente quando la funzione onAuthStateChanged
specifica che è stata apportata una modifica allo stato di autenticazione.
Verificare le modifiche
Il layout principale nel file src/app/layout.js
esegue il rendering dell'intestazione e passa l'utente, se disponibile, come prop.
<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 ciò che hai creato.
- Crea un commit con il messaggio "Mostra stato accesso" ed esegui il push nel tuo repository GitHub.
- Apri la pagina Hosting app nella Console Firebase e attendi il completamento del nuovo implementazione.
- Verifica il nuovo comportamento di autenticazione:
- Nel browser, aggiorna l'app web. Il tuo nome visualizzato viene visualizzato nell'intestazione.
- Esci e accedi di nuovo. La pagina viene aggiornata in tempo reale senza un aggiornamento della pagina. Puoi ripetere questo passaggio con utenti diversi.
- (Facoltativo) Fai clic con il tasto destro del mouse sull'app web, seleziona Visualizza il codice sorgente della pagina e cerca il nome visualizzato. Viene visualizzato nel codice sorgente HTML non elaborato restituito dal server.
7. Visualizzare le informazioni del ristorante
L'app web include dati simulati per 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, nella pagina Database Firestore, seleziona ristoranti. Nella raccolta dei ristoranti vengono visualizzati i documenti di primo livello, ciascuno dei quali rappresenta un ristorante.
- Fai clic su alcuni documenti per esplorare le proprietà di un documento del ristorante.
Visualizza 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 dei 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 "Leggi l'elenco dei ristoranti da Firestore" 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, aggiorna la pagina. Le immagini dei ristoranti vengono visualizzate sotto forma di riquadri nella pagina.
Verificare che le schede dei ristoranti vengano caricate in fase di esecuzione del server
Quando utilizzi il framework Next.js, potrebbe non essere chiaro 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 rigenerate tramite il codice JavaScript lato client.
- In DevTools, riattiva JavaScript.
Monitora 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, incluso il codice di recupero dei dati di Firebase.
Il file src/components/RestaurantListings.jsx
è un componente client e può essere configurato per eseguire l'idratazione del markup visualizzato sul 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 per te:
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 vengono applicate all'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 dati aggiornati sul numero di valutazioni e sulla 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 di 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"),
});
}
Aggiungere recensioni per un ristorante
Hai implementato il supporto per l'invio delle recensioni, quindi ora puoi verificare che le recensioni vengano 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 Hosting app nella Console Firebase e attendi il completamento del nuovo 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, individua 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. Carichi l'immagine su Firebase Storage e aggiorni 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 un documento del 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 "Consenti agli utenti di modificare la foto di ogni ristorante" 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, verifica di aver eseguito l'accesso e seleziona un ristorante.
- Fai clic su e carica un'immagine dal tuo file system. L'immagine esce dall'ambiente locale e viene caricata su Cloud Storage. L'immagine viene visualizzata immediatamente dopo il caricamento.
- Vai a Cloud Storage per 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 di riepilogo delle 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 il messaggio "Utilizza l'IA per riassumere le recensioni" ed esegui il push nel tuo repository GitHub.
- Apri la pagina Hosting app nella Console Firebase e attendi il completamento del nuovo implementazione.
- Apri una 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 funzionalità a un'app Next.js. Nello specifico, hai utilizzato quanto segue:
- Firebase App Hosting per creare ed eseguire automaticamente il deployment del codice Next.js ogni volta che esegui il push in un ramo configurato.
- Firebase Authentication per abilitare le funzionalità di accesso e di uscita.
- Cloud Firestore per i dati dei ristoranti e delle recensioni dei ristoranti.
- Cloud Storage for Firebase per le immagini dei ristoranti.