Integre o Firebase com um aplicativo Next.js

1. Antes de começar

Neste codelab, você aprenderá como integrar o Firebase a um app da Web Next.js chamado Friendly Eats, que é um site para avaliações de restaurantes.

Aplicativo da web Friendly Eats

O aplicativo da web completo oferece recursos úteis que demonstram como o Firebase pode ajudá-lo a criar aplicativos Next.js. Esses recursos incluem o seguinte:

  • Funcionalidade de login com o Google e logout: o aplicativo da web completo permite que você faça login com o Google e saia. O login e a persistência do usuário são gerenciados inteiramente por meio do Firebase Authentication .
  • Imagens: o aplicativo da web completo permite que usuários conectados carreguem imagens de restaurantes. Os recursos de imagem são armazenados no Cloud Storage para Firebase . O SDK JavaScript do Firebase fornece um URL público para imagens enviadas. Esse URL público é então armazenado no documento do restaurante relevante no Cloud Firestore .
  • Avaliações: o aplicativo da web completo permite que usuários conectados postem avaliações de restaurantes que consistem em uma classificação por estrelas e uma mensagem de texto. As informações de revisão são armazenadas no Cloud Firestore.
  • Filtros: o aplicativo da web completo permite que usuários conectados filtrem a lista de restaurantes com base em categoria, localização e preço. Você também pode personalizar o método de classificação usado. Os dados são acessados ​​no Cloud Firestore e as consultas do Firestore são aplicadas com base nos filtros usados.

Pré-requisitos

  • Conhecimento de Next.js e JavaScript

O que você aprenderá

  • Como usar o Firebase com o Next.js App Router e renderização no lado do servidor.
  • Como persistir imagens no Cloud Storage para Firebase.
  • Como ler e gravar dados em um banco de dados Cloud Firestore.
  • Como usar o login com o Google com o SDK JavaScript do Firebase.

O que você precisará

  • Git
  • O kit de desenvolvimento Java
  • Uma versão estável recente do Node.js
  • Um navegador de sua preferência, como Google Chrome
  • Um ambiente de desenvolvimento com editor de código e terminal
  • Uma conta Google para a criação e gerenciamento do seu projeto Firebase
  • A capacidade de atualizar seu projeto Firebase para o plano de preços Blaze

2. Configure seu ambiente de desenvolvimento

Este codelab fornece a base de código inicial do app e depende da CLI do Firebase.

Baixe o repositório

  1. No seu terminal, clone o repositório GitHub do codelab:
    git clone https://github.com/firebase/friendlyeats-web.git
    
  2. O repositório GitHub contém exemplos de projetos para múltiplas plataformas. No entanto, este codelab usa apenas o diretório nextjs-start . Observe os seguintes diretórios:
    • nextjs-start : contém o código inicial sobre o qual você constrói.
    • nextjs-end : contém o código da solução para o aplicativo web finalizado.
  3. No seu terminal, navegue até o diretório nextjs-start e instale as dependências necessárias:
    cd friendlyeats-web/nextjs-start
    npm install
    

Instale ou atualize a CLI do Firebase

Execute o seguinte comando para verificar se a Firebase CLI está instalada e se ela é v12.5.4 ou superior:

firebase --version
  • Se você tiver a CLI do Firebase instalada, mas ela não for a versão 12.5.4 ou superior, atualize-a:
    npm update -g firebase-tools
    
  • Se você não tiver a CLI do Firebase instalada, instale-a:
    npm install -g firebase-tools
    

Se você não conseguir instalar a CLI do Firebase devido a erros de permissão, consulte a documentação do npm ou use outra opção de instalação .

Faça login no Firebase

  1. Execute o seguinte comando para fazer login na CLI do Firebase:
    firebase login
    
  2. Dependendo se você deseja que o Firebase colete dados, insira Y ou N .
  3. No seu navegador, selecione sua conta do Google e clique em Permitir .

3. Configure seu projeto Firebase

Nesta seção, você configurará um projeto do Firebase e associará um aplicativo da Web do Firebase a ele. Você também configurará os serviços do Firebase usados ​​pelo aplicativo da Web de exemplo.

Crie um projeto do Firebase

  1. No console do Firebase , clique em Criar projeto .
  2. Na caixa de texto Digite o nome do seu projeto , insira FriendlyEats Codelab (ou um nome de projeto de sua escolha) e clique em Continuar .
  3. Para este codelab, você não precisa do Google Analytics, então desative a opção Ativar Google Analytics para este projeto .
  4. Clique em Criar projeto .
  5. Aguarde o provisionamento do seu projeto e clique em Continuar .
  6. No seu projeto do Firebase, vá para Configurações do projeto . Anote o ID do seu projeto porque você precisará dele mais tarde. Esse identificador exclusivo é como seu projeto é identificado (por exemplo, na Firebase CLI).

Adicione um aplicativo da web ao seu projeto do Firebase

  1. Navegue até a visão geral do projeto no projeto do Firebase e clique em e41f2efdd9539c31.png Rede .
  2. Na caixa de texto Apelido do aplicativo , insira um apelido de aplicativo memorável, como My Next.js app .
  3. Marque a caixa de seleção Configurar também o Firebase Hosting para este aplicativo .
  4. Clique em Registrar aplicativo > Próximo > Próximo > Continuar para console .

Atualize seu plano de preços do Firebase

Para usar estruturas da Web, seu projeto do Firebase precisa estar no plano de preços Blaze , o que significa que está associado a uma conta do Cloud Billing .

  • Uma conta Cloud Billing requer uma forma de pagamento, como um cartão de crédito.
  • Se você é novo no Firebase e no Google Cloud, verifique se você está qualificado para um crédito de US$ 300 e uma conta de avaliação gratuita do Cloud Billing .

No entanto, observe que a conclusão deste codelab não gerará cobranças reais.

Para atualizar seu projeto para o plano Blaze, siga estas etapas:

  1. No console do Firebase, selecione para atualizar seu plano .
  2. Na caixa de diálogo, selecione o plano Blaze e siga as instruções na tela para associar seu projeto a uma conta do Cloud Billing.
    Se você precisasse criar uma conta do Cloud Billing, talvez fosse necessário navegar de volta ao fluxo de upgrade no Console do Firebase para concluir o upgrade.

Configure os serviços do Firebase no Firebase Console

Configurar autenticação

  1. No console do Firebase, navegue até Autenticação .
  2. Clique em Começar .
  3. Na coluna Provedores adicionais , clique em Google > Ativar .
  4. Na caixa de texto Nome público para o projeto , insira um nome memorável, como My Next.js app .
  5. No menu suspenso Email de suporte para projeto , selecione seu endereço de email.
  6. Clique em Salvar .

Configurar o Cloud Firestore

  1. No console do Firebase, navegue até Firestore .
  2. Clique em Criar banco de dados > Iniciar no modo de teste > Avançar .
    Posteriormente neste codelab, você adicionará regras de segurança para proteger seus dados. Não distribua ou exponha um aplicativo publicamente sem adicionar regras de segurança ao seu banco de dados .
  3. Use o local padrão ou selecione um local de sua preferência.
    Para um aplicativo real, você deseja escolher um local próximo aos seus usuários. Observe que esse local não pode ser alterado posteriormente e também será automaticamente o local do seu intervalo padrão do Cloud Storage (próxima etapa).
  4. Clique em Concluído .

Configurar o Cloud Storage para Firebase

  1. No console do Firebase, navegue até Storage .
  2. Clique em Começar > Iniciar em modo de teste > Próximo .
    Posteriormente neste codelab, você adicionará regras de segurança para proteger seus dados. Não distribua ou exponha um aplicativo publicamente sem adicionar regras de segurança ao seu bucket de armazenamento .
  3. A localização do seu bucket já deve estar selecionada (devido à configuração do Firestore na etapa anterior).
  4. Clique em Concluído .

4. Revise a base de código inicial

Nesta seção, você analisará algumas áreas da base de código inicial do app às quais adicionará funcionalidades neste codelab.

Estrutura de pastas e arquivos

A tabela a seguir contém uma visão geral da estrutura de pastas e arquivos do aplicativo:

Pastas e arquivos

Descrição

src/components

Componentes React para filtros, cabeçalhos, detalhes de restaurantes e avaliações

src/lib

Funções utilitárias que não estão necessariamente vinculadas ao React ou Next.js

src/lib/firebase

Código específico do Firebase e configuração do Firebase

public

Ativos estáticos no aplicativo Web, como ícones

src/app

Roteamento com o roteador de aplicativo Next.js

src/app/restaurant

Um manipulador de rota de API

package.json e package-lock.json

Dependências do projeto com npm

next.config.js

Configuração específica do Next.js (as ações do servidor estão habilitadas )

jsconfig.json

Configuração do serviço de linguagem JavaScript

Componentes de servidor e cliente

O aplicativo é um aplicativo da web Next.js que usa o App Router . A renderização do servidor é usada em todo o aplicativo. Por exemplo, o arquivo src/app/page.js é um componente do servidor responsável pela página principal. O arquivo src/components/RestaurantListings.jsx é um componente cliente indicado pela diretiva "use client" no início do arquivo.

Instruções de importação

Você pode notar instruções de importação como as seguintes:

import RatingPicker from "@/src/components/RatingPicker.jsx";

O aplicativo usa o símbolo @ para evitar caminhos de importação relativos desajeitados e é possível graças a aliases de caminho .

APIs específicas do Firebase

Todo o código da API do Firebase está agrupado no diretório src/lib/firebase . Os componentes individuais do React importam as funções agrupadas do diretório src/lib/firebase , em vez de importar as funções do Firebase diretamente.

Dados simulados

Os dados simulados de restaurantes e avaliações estão contidos no arquivo src/lib/randomData.js . Os dados desse arquivo são montados no código do arquivo src/lib/fakeRestaurants.js .

5. Configure a hospedagem local com o emulador Firebase Hosting

Nesta seção, você usará o emulador do Firebase Hosting para executar o aplicativo da Web Next.js localmente.

Ao final desta seção, o emulador do Firebase Hosting executa o aplicativo Next.js para você, portanto, não é necessário executar o Next.js em um processo separado dos emuladores.

Baixe e use uma conta de serviço do Firebase

O aplicativo da Web que você criará neste codelab usa renderização no servidor com Next.js .

O SDK Admin do Firebase para Node.js é usado para garantir que as regras de segurança funcionem no código do lado do servidor. Para usar APIs no Firebase Admin, você precisa fazer download e usar uma conta de serviço do Firebase no Console do Firebase.

  1. No console do Firebase, navegue até a página Contas de serviço nas configurações do projeto .
  2. Clique em Gerar nova chave privada > Gerar chave .
  3. Após o download do arquivo para o seu sistema de arquivos, obtenha o caminho completo para esse arquivo.
    Por exemplo, se você baixou o arquivo para o diretório Downloads , o caminho completo pode ser assim: /Users/me/Downloads/my-project-id-firebase-adminsdk-123.json
  4. No seu terminal, defina a variável de ambiente GOOGLE_APPLICATION_CREDENTIALS para o caminho da sua chave privada baixada. Em um ambiente Unix, o comando pode ser assim:
    export GOOGLE_APPLICATION_CREDENTIALS="/Users/me/Downloads/my-project-id-firebase-adminsdk-123.json"
    
  5. Mantenha este terminal aberto e use-o no restante deste codelab, pois sua variável de ambiente poderá ser perdida se você iniciar uma nova sessão de terminal.
    Se você abrir uma nova sessão de terminal, deverá executar novamente o comando anterior.

Adicione a configuração do Firebase ao código do seu aplicativo da web

  1. No console do Firebase, navegue até as configurações do projeto .
  2. No painel de instalação e configuração do SDK , encontre a variável firebaseConfig e copie suas propriedades e seus valores.
  3. Abra o arquivo .env em seu editor de código e preencha os valores das variáveis ​​de ambiente com os valores de configuração do console do Firebase.
  4. No arquivo, substitua as propriedades existentes pelas que você copiou.
  5. Salve o arquivo.

Inicialize o aplicativo da web com seu projeto do Firebase

Para conectar o aplicativo da web ao seu projeto do Firebase, siga estas etapas:

  1. No seu terminal, certifique-se de que os frameworks web estejam habilitados no Firebase:
    firebase experiments:enable webframeworks
    
  2. Inicialize o Firebase:
    firebase init
    
  3. Selecione as seguintes opções:
    • Firestore: configure regras de segurança e indexe arquivos para Firestore
    • Hosting: configure arquivos para o Firebase Hosting e (opcionalmente) configure implantações do GitHub Action
    • Armazenamento: configure um arquivo de regras de segurança para o Cloud Storage
    • Emuladores: configure emuladores locais para produtos Firebase
  4. Selecione Usar um projeto existente e insira o ID do projeto anotado anteriormente.
  5. Selecione os valores padrão para todas as perguntas subsequentes até chegar à pergunta Em qual região você gostaria de hospedar conteúdo do lado do servidor, se aplicável? . O terminal exibe uma mensagem informando que detecta uma base de código Next.js existente no diretório atual.
  6. Para a pergunta Em qual região você gostaria de hospedar conteúdo do lado do servidor, se aplicável? , selecione o local selecionado anteriormente para Firestore e Cloud Storage.
  7. Selecione os valores padrão para todas as perguntas subsequentes até chegar à pergunta Quais emuladores do Firebase você deseja configurar? . Para esta pergunta, selecione Emulador de funções e Emulador de hospedagem .
  8. Selecione os valores padrão para todas as outras perguntas.

Implantar regras de segurança

O código já possui conjuntos de regras de segurança para Firestore e Cloud Storage para Firebase. Depois de implantar as regras de segurança, os dados no banco de dados e no bucket ficam mais protegidos contra uso indevido.

  1. Para implantar essas regras de segurança, execute este comando em seu terminal:
    firebase deploy --only firestore:rules,storage
    
  2. Se lhe for perguntado: "Cloud Storage for Firebase needs an IAM Role to use cross-service rules. Grant the new role?" , selecione Sim .

Inicie o emulador de hospedagem

  1. No seu terminal, inicie o emulador Hosting:
    firebase emulators:start --only hosting
    
    Seu terminal responde com a porta onde você pode encontrar o emulador Hosting, por exemplo http://localhost:5000/ .

Terminal mostrando que o Hosting Emulator está pronto

  1. No seu navegador, navegue até o URL com o emulador do Firebase Hosting.
  2. Se você vir o erro na página da web que começa assim: "Error: Firebase session cookie has incorrect..." , você precisará excluir todos os seus cookies em seu ambiente localhost. Para fazer isso, siga as instruções em excluir cookies | Documentação do DevTools .

Um erro de sessão de cookie

Excluindo cookies no DevTools

Agora você pode ver o aplicativo web inicial! Mesmo que você esteja visualizando o aplicativo da web em um URL de host local, ele usa serviços reais do Firebase que você configurou em seu console.

6. Adicione autenticação ao aplicativo web

Nesta seção, você adiciona autenticação ao aplicativo Web para poder fazer login nele.

Implementar as funções de entrada e saída

  1. No arquivo src/lib/firebase/auth.js , substitua as funções onAuthStateChanged , signInWithGoogle e signOut pelo seguinte código:
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);
        }
}

Este código usa as seguintes APIs do Firebase:

API do Firebase

Descrição

GoogleAuthProvider

Cria uma instância do provedor de autenticação do Google.

signInWithPopup

Inicia um fluxo de autenticação baseado em diálogo.

auth.signOut

Desconecta o usuário.

No arquivo src/components/Header.jsx , o código já invoca as funções signInWithGoogle e signOut .

  1. No aplicativo da web, atualize a página e clique em Fazer login com o Google . O aplicativo da web não é atualizado, por isso não está claro se o login foi bem-sucedido.

Assine as alterações de autenticação

Para assinar alterações de autenticação, siga estas etapas:

  1. Navegue até o arquivo src/components/Header.jsx .
  2. Substitua a função useUserSession pelo seguinte código:
function useUserSession(initialUser) {
        // The initialUser comes from the server through a server component
        const [user, setUser] = useState(initialUser);
        const router = useRouter();

        useEffect(() => {
                const unsubscribe = onAuthStateChanged(authUser => {
                        setUser(authUser);
                });
                return () => {
                        unsubscribe();
                };
        }, []);

        useEffect(() => {
                onAuthStateChanged(authUser => {
                        if (user === undefined) return;
                        if (user?.email !== authUser?.email) {
                                router.refresh();
                        }
                });
        }, [user]);

        return user;
}

Este código usa um gancho de estado React para atualizar o usuário quando a função onAuthStateChanged especifica que há uma alteração no estado de autenticação.

Verifique as alterações

O layout raiz no arquivo src/app/layout.js renderiza o cabeçalho e passa o usuário, se disponível, como um suporte.

<Header initialUser={currentUser?.toJSON()} />

Isso significa que o componente <Header> renderiza os dados do usuário, se disponíveis, durante o tempo de execução do servidor. Se houver atualizações de autenticação durante o ciclo de vida da página após o carregamento inicial da página, o manipulador onAuthStateChanged as tratará.

Agora é hora de testar o aplicativo web e verificar o que você construiu.

Para verificar o novo comportamento de autenticação, siga estas etapas:

  1. No seu navegador, atualize o aplicativo da web. Seu nome de exibição aparece no cabeçalho.
  2. Saia e faça login novamente. A página é atualizada em tempo real sem atualização da página. Você pode repetir esta etapa com usuários diferentes.
  3. Opcional: clique com o botão direito no aplicativo Web, selecione Exibir origem da página e pesquise o nome de exibição. Ele aparece na fonte HTML bruta retornada do servidor.

7. Veja informações do restaurante

O aplicativo da web inclui dados simulados para restaurantes e avaliações.

Adicione um ou mais restaurantes

Para inserir dados simulados de restaurantes em seu banco de dados local do Cloud Firestore, siga estas etapas:

  1. No aplicativo da web, selecione 2cf67d488d8e6332.png > Adicione exemplos de restaurantes .
  2. No console do Firebase, na página do banco de dados do Firestore , selecione restaurantes . Você vê os documentos de nível superior na coleção de restaurantes, cada um representando um restaurante.
  3. Clique em alguns documentos para explorar as propriedades de um documento de restaurante.

Exibir a lista de restaurantes

Seu banco de dados do Cloud Firestore agora tem restaurantes que o aplicativo da web Next.js pode exibir.

Para definir o código de busca de dados, siga estas etapas:

  1. No arquivo src/app/page.js , encontre o componente do servidor <Home /> e revise a chamada para a função getRestaurants , que recupera uma lista de restaurantes em tempo de execução do servidor. Você implementa a função getRestaurants nas etapas a seguir.
  2. No arquivo src/lib/firebase/firestore.js , substitua as funções applyQueryFilters e getRestaurants pelo seguinte código:
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(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(),
                };
        });
}
  1. Atualize o aplicativo da web. As imagens do restaurante aparecem como blocos na página.

Verifique se as listagens de restaurantes são carregadas no tempo de execução do servidor

Usando a estrutura Next.js, pode não ser óbvio quando os dados são carregados no tempo de execução do servidor ou no tempo de execução do lado do cliente.

Para verificar se as listagens de restaurantes são carregadas no tempo de execução do servidor, siga estas etapas:

  1. No aplicativo da web, abra o DevTools e desative o JavaScript .

Desative o JavaScipt no DevTools

  1. Atualize o aplicativo da web. As listas de restaurantes ainda carregam. As informações do restaurante são retornadas na resposta do servidor. Quando o JavaScript está ativado, as informações do restaurante são hidratadas por meio do código JavaScript do lado do cliente.
  2. No DevTools, reative o JavaScript .

Ouça atualizações de restaurantes com ouvintes de snapshots do Cloud Firestore

Na seção anterior, você viu como o conjunto inicial de restaurantes foi carregado do arquivo src/app/page.js . O arquivo src/app/page.js é um componente do servidor e é renderizado no servidor, incluindo o código de busca de dados do Firebase.

O arquivo src/components/RestaurantListings.jsx é um componente cliente e pode ser configurado para hidratar a marcação renderizada pelo servidor.

Para configurar o arquivo src/components/RestaurantListings.jsx para hidratar a marcação renderizada pelo servidor, siga estas etapas:

  1. No arquivo src/components/RestaurantListings.jsx , observe o seguinte código, que já foi escrito para você:
useEffect(() => {
        const unsubscribe = getRestaurantsSnapshot(data => {
                setRestaurants(data);
        }, filters);

        return () => {
                unsubscribe();
        };
}, [filters]);

Este código invoca a função getRestaurantsSnapshot() , que é semelhante à função getRestaurants() que você implementou em uma etapa anterior. No entanto, esta função de instantâneo fornece um mecanismo de retorno de chamada para que o retorno de chamada seja invocado sempre que uma alteração for feita na coleção do restaurante.

  1. No arquivo src/lib/firebase/firestore.js , substitua a função getRestaurantsSnapshot() pelo seguinte código:
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;
}

As alterações feitas na página do banco de dados do Firestore agora são refletidas no aplicativo da web em tempo real.

  1. No aplicativo da web, selecione 27ca5d1e8ed8adfe.png > Adicione exemplos de restaurantes . Se a sua função de instantâneo for implementada corretamente, os restaurantes aparecerão em tempo real sem atualização da página.

8. Salve os dados do usuário do aplicativo da web

  1. No arquivo src/lib/firebase/firestore.js , substitua a função updateWithRating() pelo seguinte código:
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()),
        });
};

Este código insere um novo documento do Firestore representando a nova revisão. O código também atualiza o documento existente do Firestore que representa o restaurante com números atualizados para o número de avaliações e a classificação média calculada.

  1. Substitua a função addReviewToRestaurant() pelo seguinte código:
export async function addReviewToRestaurant(db, restaurantId, review) {
        if (!restaurantId) {
                throw new Error("No restaurant ID was 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`)
                );

                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;
        }
}

Implementar uma ação de servidor Next.js

Uma ação do servidor Next.js fornece uma API conveniente para acessar dados do formulário, como data.get("text") para obter o valor do texto da carga útil de envio do formulário.

Para usar uma ação do servidor Next.js para processar o envio do formulário de revisão, siga estas etapas:

  1. No arquivo src/components/ReviewDialog.jsx , encontre o action no elemento <form> .
<form action={handleReviewFormSubmission}>

O valor do atributo action refere-se a uma função que você implementará na próxima etapa.

  1. No arquivo src/app/actions.js , substitua a função handleReviewFormSubmission() pelo seguinte código:
// 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"),
        });
}

Adicione avaliações sobre um restaurante

Você implementou suporte para envio de avaliações, então agora pode verificar se suas avaliações foram inseridas corretamente no Cloud Firestore.

Para adicionar uma avaliação e verificar se ela está inserida no Cloud Firestore, siga estas etapas:

  1. No aplicativo web, selecione um restaurante na página inicial.
  2. Na página do restaurante, clique em 3e19beef78bb0d0e.png .
  3. Selecione uma classificação por estrelas.
  4. Escreva uma crítica.
  5. Clique em Enviar . Sua avaliação aparece no topo da lista de avaliações.
  6. No Cloud Firestore, pesquise no painel Adicionar documento o documento do restaurante que você revisou e selecione-o.
  7. No painel Iniciar coleta , selecione avaliações .
  8. No painel Adicionar documento , encontre o documento para revisão para verificar se ele foi inserido conforme esperado.

Documentos no emulador Firestore

9. Salve os arquivos enviados pelo usuário do aplicativo da web

Nesta seção, você adiciona funcionalidade para poder substituir a imagem associada a um restaurante quando estiver conectado. Faça upload da imagem para o Firebase Storage e atualize o URL da imagem no documento do Cloud Firestore que representa o restaurante.

Para salvar arquivos enviados pelo usuário do aplicativo da web, siga estas etapas:

  1. No arquivo src/components/Restaurant.jsx , observe o código que é executado quando o usuário faz upload de um arquivo:
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 });
}

Nenhuma alteração é necessária, mas você implementa o comportamento da função updateRestaurantImage() nas etapas a seguir.

  1. No arquivo src/lib/firebase/storage.js , substitua as funções updateRestaurantImage() e uploadImage() pelo seguinte código:
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);
}

A função updateRestaurantImageReference() já está implementada para você. Esta função atualiza um documento de restaurante existente no Cloud Firestore com um URL de imagem atualizado.

Verifique a funcionalidade de upload de imagens

Para verificar se a imagem é carregada conforme esperado, siga estas etapas:

  1. No aplicativo da web, verifique se você está conectado e selecione um restaurante.
  2. Clique 7067eb41fea41ff0.png e carregue uma imagem do seu sistema de arquivos. Sua imagem sai do ambiente local e é enviada para o Cloud Storage. A imagem aparece imediatamente após você carregá-la.
  3. Navegue até Cloud Storage para Firebase.
  4. Navegue até a pasta que representa o restaurante. A imagem que você carregou existe na pasta.

6cf3f9e2303c931c.png

10. Conclusão

Parabéns! Você aprendeu como usar o Firebase para adicionar recursos e funcionalidades a um aplicativo Next.js. Especificamente, você usou o seguinte:

Saber mais

,

1. Antes de começar

Neste codelab, você aprenderá como integrar o Firebase a um app da Web Next.js chamado Friendly Eats, que é um site para avaliações de restaurantes.

Aplicativo web Friendly Eats

O aplicativo da web completo oferece recursos úteis que demonstram como o Firebase pode ajudá-lo a criar aplicativos Next.js. Esses recursos incluem o seguinte:

  • Funcionalidade de login com o Google e logout: o aplicativo da web completo permite que você faça login com o Google e saia. O login e a persistência do usuário são gerenciados inteiramente por meio do Firebase Authentication .
  • Imagens: o aplicativo da web completo permite que usuários conectados carreguem imagens de restaurantes. Os recursos de imagem são armazenados no Cloud Storage para Firebase . O SDK JavaScript do Firebase fornece um URL público para imagens enviadas. Esse URL público é então armazenado no documento do restaurante relevante no Cloud Firestore .
  • Avaliações: o aplicativo da web completo permite que usuários conectados postem avaliações de restaurantes que consistem em uma classificação por estrelas e uma mensagem de texto. As informações de revisão são armazenadas no Cloud Firestore.
  • Filtros: o aplicativo da web completo permite que usuários conectados filtrem a lista de restaurantes com base em categoria, localização e preço. Você também pode personalizar o método de classificação usado. Os dados são acessados ​​no Cloud Firestore e as consultas do Firestore são aplicadas com base nos filtros usados.

Pré-requisitos

  • Conhecimento de Next.js e JavaScript

O que você aprenderá

  • Como usar o Firebase com o Next.js App Router e renderização no lado do servidor.
  • Como persistir imagens no Cloud Storage para Firebase.
  • Como ler e gravar dados em um banco de dados Cloud Firestore.
  • Como usar o login com o Google com o SDK JavaScript do Firebase.

O que você precisará

  • Git
  • O kit de desenvolvimento Java
  • Uma versão estável recente do Node.js
  • Um navegador de sua preferência, como Google Chrome
  • Um ambiente de desenvolvimento com editor de código e terminal
  • Uma conta Google para a criação e gerenciamento do seu projeto Firebase
  • A capacidade de atualizar seu projeto Firebase para o plano de preços Blaze

2. Configure seu ambiente de desenvolvimento

Este codelab fornece a base de código inicial do app e depende da CLI do Firebase.

Baixe o repositório

  1. No seu terminal, clone o repositório GitHub do codelab:
    git clone https://github.com/firebase/friendlyeats-web.git
    
  2. O repositório GitHub contém exemplos de projetos para múltiplas plataformas. No entanto, este codelab usa apenas o diretório nextjs-start . Observe os seguintes diretórios:
    • nextjs-start : contém o código inicial sobre o qual você constrói.
    • nextjs-end : contém o código da solução para o aplicativo web finalizado.
  3. No seu terminal, navegue até o diretório nextjs-start e instale as dependências necessárias:
    cd friendlyeats-web/nextjs-start
    npm install
    

Instale ou atualize a CLI do Firebase

Execute o seguinte comando para verificar se a Firebase CLI está instalada e se ela é v12.5.4 ou superior:

firebase --version
  • Se você tiver a CLI do Firebase instalada, mas ela não for a versão 12.5.4 ou superior, atualize-a:
    npm update -g firebase-tools
    
  • Se você não tiver a CLI do Firebase instalada, instale-a:
    npm install -g firebase-tools
    

Se você não conseguir instalar a CLI do Firebase devido a erros de permissão, consulte a documentação do npm ou use outra opção de instalação .

Faça login no Firebase

  1. Execute o seguinte comando para fazer login na CLI do Firebase:
    firebase login
    
  2. Dependendo se você deseja que o Firebase colete dados, insira Y ou N .
  3. No seu navegador, selecione sua conta do Google e clique em Permitir .

3. Configure seu projeto Firebase

Nesta seção, você configurará um projeto do Firebase e associará um aplicativo da Web do Firebase a ele. Você também configurará os serviços do Firebase usados ​​pelo aplicativo da Web de exemplo.

Crie um projeto do Firebase

  1. No console do Firebase , clique em Criar projeto .
  2. Na caixa de texto Digite o nome do seu projeto , insira FriendlyEats Codelab (ou um nome de projeto de sua escolha) e clique em Continuar .
  3. Para este codelab, você não precisa do Google Analytics, então desative a opção Ativar Google Analytics para este projeto .
  4. Clique em Criar projeto .
  5. Aguarde o provisionamento do seu projeto e clique em Continuar .
  6. No seu projeto do Firebase, vá para Configurações do projeto . Anote o ID do seu projeto porque você precisará dele mais tarde. Esse identificador exclusivo é como seu projeto é identificado (por exemplo, na CLI do Firebase).

Adicione um aplicativo da web ao seu projeto do Firebase

  1. Navegue até a visão geral do projeto no projeto do Firebase e clique em e41f2efdd9539c31.png Rede .
  2. Na caixa de texto Apelido do aplicativo , insira um apelido de aplicativo memorável, como My Next.js app .
  3. Marque a caixa de seleção Configurar também o Firebase Hosting para este aplicativo .
  4. Clique em Registrar aplicativo > Próximo > Próximo > Continuar para console .

Atualize seu plano de preços do Firebase

Para usar estruturas da Web, seu projeto do Firebase precisa estar no plano de preços Blaze , o que significa que está associado a uma conta do Cloud Billing .

  • Uma conta Cloud Billing requer uma forma de pagamento, como um cartão de crédito.
  • Se você é novo no Firebase e no Google Cloud, verifique se você está qualificado para um crédito de US$ 300 e uma conta de avaliação gratuita do Cloud Billing .

No entanto, observe que a conclusão deste codelab não gerará cobranças reais.

Para atualizar seu projeto para o plano Blaze, siga estas etapas:

  1. No console do Firebase, selecione para atualizar seu plano .
  2. Na caixa de diálogo, selecione o plano Blaze e siga as instruções na tela para associar seu projeto a uma conta do Cloud Billing.
    Se você precisasse criar uma conta do Cloud Billing, talvez fosse necessário navegar de volta ao fluxo de upgrade no Console do Firebase para concluir o upgrade.

Configure os serviços do Firebase no Firebase Console

Configurar autenticação

  1. No console do Firebase, navegue até Autenticação .
  2. Clique em Começar .
  3. Na coluna Provedores adicionais , clique em Google > Ativar .
  4. Na caixa de texto Nome público para o projeto , insira um nome memorável, como My Next.js app .
  5. No menu suspenso Email de suporte para projeto , selecione seu endereço de email.
  6. Clique em Salvar .

Configurar o Cloud Firestore

  1. No console do Firebase, navegue até Firestore .
  2. Clique em Criar banco de dados > Iniciar no modo de teste > Avançar .
    Posteriormente neste codelab, você adicionará regras de segurança para proteger seus dados. Não distribua ou exponha um aplicativo publicamente sem adicionar regras de segurança ao seu banco de dados .
  3. Use o local padrão ou selecione um local de sua preferência.
    Para um aplicativo real, você deseja escolher um local próximo aos seus usuários. Observe que esse local não pode ser alterado posteriormente e também será automaticamente o local do seu intervalo padrão do Cloud Storage (próxima etapa).
  4. Clique em Concluído .

Configurar o Cloud Storage para Firebase

  1. No console do Firebase, navegue até Storage .
  2. Clique em Começar > Iniciar em modo de teste > Próximo .
    Posteriormente neste codelab, você adicionará regras de segurança para proteger seus dados. Não distribua nem exponha um aplicativo publicamente sem adicionar regras de segurança ao seu bucket de armazenamento .
  3. A localização do seu bucket já deve estar selecionada (devido à configuração do Firestore na etapa anterior).
  4. Clique em Concluído .

4. Revise a base de código inicial

Nesta seção, você revisará algumas áreas da base de código inicial do aplicativo à qual adicionará a funcionalidade neste código.

Estrutura de pasta e arquivo

A tabela a seguir contém uma visão geral da pasta e estrutura de arquivos do aplicativo:

Pastas e arquivos

Descrição

src/components

Reaja componentes para filtros, cabeçalhos, detalhes do restaurante e críticas

src/lib

Funções de utilidade que não são necessariamente obrigadas a reagir ou next.js

src/lib/firebase

Código específico do Firebase e configuração de Firebase

public

Ativos estáticos no aplicativo da web, como ícones

src/app

Roteamento com o roteador App Next.js

src/app/restaurant

Um manipulador de rota da API

package.json e package-lock.json

Dependências do projeto com NPM

next.config.js

Configuração específica de JS (ações do servidor estão ativadas )

jsconfig.json

Configuração de serviço de idioma JavaScript

Componentes de servidor e cliente

O aplicativo é um aplicativo Next.js Web que usa o roteador de aplicativos . A renderização do servidor é usada em todo o aplicativo. Por exemplo, o arquivo src/app/page.js é um componente de servidor responsável pela página principal. O arquivo src/components/RestaurantListings.jsx é um componente cliente indicado pela diretiva "use client" no início do arquivo.

Declarações de importação

Você pode notar declarações de importação como o seguinte:

import RatingPicker from "@/src/components/RatingPicker.jsx";

O aplicativo usa o símbolo @ para evitar caminhos de importação relativa desajeitada e é possível pelos aliases do caminho .

APIs específicas de Firebase

Todo o código da API do Firebase está envolvido no diretório src/lib/firebase . Os componentes de reação individuais importam as funções embrulhadas do diretório src/lib/firebase , em vez de importar diretamente as funções do Firebase.

Dados simulados

Os dados simulados de restaurantes e revisões estão contidos no arquivo src/lib/randomData.js . Os dados desse arquivo são montados no código no arquivo src/lib/fakeRestaurants.js .

5. Configure a hospedagem local com o Emulador de hospedagem de Firebase

Nesta seção, você usará o Emulador de hospedagem do Firebase para executar o App Next.js Web localmente.

No final desta seção, o Emulador de hospedagem do Firebase executa o aplicativo Next.js para você, para que você não precise executar o próximo.js em um processo separado para os emuladores.

Baixe e use uma conta de serviço do Firebase

O aplicativo da web que você criará neste código usa a renderização do lado do servidor no Next.js.

O Firebase Admin SDK para Node.js é usado para garantir que as regras de segurança estejam funcionais a partir do código lateral do servidor. Para usar as APIs no Firebase Admin, você precisa baixar e usar uma conta de serviço do Firebase no console do Firebase.

  1. No console do Firebase, navegue até a página Contas de Serviço nas configurações do seu projeto .
  2. Clique em Gerar nova chave privada > Gere a tecla .
  3. Depois que o arquivo é baixado para o seu sistema de arquivos, obtenha o caminho completo para esse arquivo.
    Por exemplo, se você baixou o arquivo para o seu diretório de downloads , o caminho completo pode parecer o seguinte: /Users/me/Downloads/my-project-id-firebase-adminsdk-123.json
  4. No seu terminal, defina a variável de ambiente GOOGLE_APPLICATION_CREDENTIALS no caminho da sua chave privada baixada. Em um ambiente Unix, o comando pode ser assim:
    export GOOGLE_APPLICATION_CREDENTIALS="/Users/me/Downloads/my-project-id-firebase-adminsdk-123.json"
    
  5. Mantenha este terminal aberto e use -o para o restante deste código, pois sua variável de ambiente pode ser perdida se você iniciar uma nova sessão de terminal.
    Se você abrir uma nova sessão de terminal, deve executar novamente o comando anterior.

Adicione sua configuração de Firebase ao seu código de aplicativo da web

  1. No console do Firebase, navegue até as configurações do seu projeto .
  2. No painel de configuração e configuração do SDK , encontre a variável firebaseConfig e copie suas propriedades e seus valores.
  3. Abra o arquivo .env no seu editor de código e preencha os valores variáveis ​​do ambiente com os valores de configuração do console do Firebase.
  4. No arquivo, substitua as propriedades existentes pelas pessoas que você copiou.
  5. Salve o arquivo.

Inicialize o aplicativo da web com seu projeto Firebase

Para conectar o aplicativo da web ao seu projeto Firebase, siga estas etapas:

  1. No seu terminal, verifique se as estruturas da web estão ativadas no FireBase:
    firebase experiments:enable webframeworks
    
  2. Inicialize Firebase:
    firebase init
    
  3. Selecione as seguintes opções:
    • Firestore: configure regras de segurança e indexos arquivos para o Firestore
    • Hospedagem: Configurar arquivos para hospedagem de Firebase e (opcionalmente) configurar a ação do github implants
    • Armazenamento: Configurar um arquivo de regras de segurança para armazenamento em nuvem
    • Emuladores: Configure emuladores locais para produtos Firebase
  4. Selecione Use um projeto existente e digite o ID do projeto que você observou anteriormente.
  5. Selecione os valores padrão para todas as perguntas subsequentes até chegar à pergunta em que região você gostaria de hospedar conteúdo do lado do servidor, se aplicável? . O terminal exibe uma mensagem de que detecta uma base de código do próximo.js existente no diretório atual.
  6. Para a pergunta em que região você gostaria de hospedar conteúdo do lado do servidor, se aplicável? , selecione o local selecionado anteriormente para o Firestore e o armazenamento em nuvem.
  7. Selecione os valores padrão para todas as perguntas subsequentes até chegar à pergunta quais emuladores de Firebase você deseja configurar? . Para esta pergunta, selecione o emulador de funções e o emulador de hospedagem .
  8. Selecione os valores padrão para todas as outras perguntas.

Implantar regras de segurança

O código já possui conjuntos de regras de segurança para o Firestore e para armazenamento em nuvem para o FireBase. Depois de implantar as regras de segurança, os dados no seu banco de dados e seu balde estão melhor protegidos contra o uso indevido.

  1. Para implantar essas regras de segurança, execute este comando em seu terminal:
    firebase deploy --only firestore:rules,storage
    
  2. Se você é perguntado: "Cloud Storage for Firebase needs an IAM Role to use cross-service rules. Grant the new role?" , selecione Sim .

Inicie o emulador de hospedagem

  1. No seu terminal, inicie o emulador de hospedagem:
    firebase emulators:start --only hosting
    
    Seu terminal responde com a porta onde você pode encontrar o emulador de hospedagem, por exemplo http: // localhost: 5000/ .

Terminal mostrando que o emulador de hospedagem está pronto

  1. No seu navegador, navegue até o URL com o emulador de hospedagem de Firebase.
  2. Se você vir o erro na página da web que inicia o seguinte: "Error: Firebase session cookie has incorrect..." , você precisa excluir todos os seus cookies no ambiente do seu localhost. Para fazer isso, siga as instruções em Excluir cookies | Documentação de Devtools .

Um erro de sessão de biscoitos

Excluindo cookies em Devtools

Agora você pode ver o aplicativo da web inicial! Mesmo que você esteja visualizando o aplicativo da web em um URL de localhost, ele usa serviços reais de Firebase que você configurou em seu console.

6. Adicione a autenticação ao aplicativo da web

Nesta seção, você adiciona autenticação ao aplicativo da web para poder fazer login nela.

Implementar as funções de login e saída

  1. No arquivo src/lib/firebase/auth.js , substitua o onAuthStateChanged , signInWithGoogle e signOut com o seguinte código:
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);
        }
}

Este código usa as seguintes APIs do Firebase:

API da Firebase

Descrição

GoogleAuthProvider

Cria uma instância do provedor de autenticação do Google.

signInWithPopup

Inicia um fluxo de autenticação baseado em diálogo.

auth.signOut

Assina o usuário.

No arquivo src/components/Header.jsx , o código já chama as funções signInWithGoogle e signOut .

  1. No aplicativo da web, atualize a página e clique em entrar no Google . O aplicativo da Web não atualiza, por isso não está claro se o assinatura foi bem-sucedido.

Inscreva -se nas mudanças de autenticação

Para se inscrever nas mudanças de autenticação, siga estas etapas:

  1. Navegue até o arquivo src/components/Header.jsx .
  2. Substitua a função useUserSession pelo seguinte código:
function useUserSession(initialUser) {
        // The initialUser comes from the server through a server component
        const [user, setUser] = useState(initialUser);
        const router = useRouter();

        useEffect(() => {
                const unsubscribe = onAuthStateChanged(authUser => {
                        setUser(authUser);
                });
                return () => {
                        unsubscribe();
                };
        }, []);

        useEffect(() => {
                onAuthStateChanged(authUser => {
                        if (user === undefined) return;
                        if (user?.email !== authUser?.email) {
                                router.refresh();
                        }
                });
        }, [user]);

        return user;
}

Este código usa um gancho de estado do React para atualizar o usuário quando a função onAuthStateChanged especifica que há uma alteração no estado de autenticação.

Verifique as alterações

O layout root no arquivo src/app/layout.js renderiza o cabeçalho e passa no usuário, se disponível, como um suporte.

<Header initialUser={currentUser?.toJSON()} />

Isso significa que o componente <Header> renderiza os dados do usuário, se disponíveis, durante o tempo de execução do servidor. Se houver alguma atualização de autenticação durante o ciclo de vida da página após o carregamento inicial da página, o manipulador onAuthStateChanged lida com elas.

Agora é hora de testar o aplicativo da web e verificar o que você criou.

Para verificar o novo comportamento de autenticação, siga estas etapas:

  1. No seu navegador, atualize o aplicativo da web. Seu nome de exibição aparece no cabeçalho.
  2. Sair e fazer login novamente. A página é atualizada em tempo real sem uma atualização de página. Você pode repetir esta etapa com usuários diferentes.
  3. Opcional: clique com o botão direito do mouse no aplicativo da web, selecione Exibir a fonte da página e pesquise o nome de exibição. Aparece na fonte HTML bruta retornada do servidor.

7. Veja as informações do restaurante

O aplicativo da web inclui dados simulados para restaurantes e críticas.

Adicione um ou mais restaurantes

Para inserir dados simulados de restaurantes em seu banco de dados local em nuvem Firestore, siga estas etapas:

  1. No aplicativo da web, selecione 2CF67D488D8E6332.png > Adicione amostra de restaurantes .
  2. No console do Firebase na página de banco de dados Firestore , selecione restaurantes . Você vê os documentos de nível superior na coleção de restaurantes, cada um dos quais representa um restaurante.
  3. Clique em alguns documentos para explorar as propriedades de um documento de restaurante.

Exibir a lista de restaurantes

Seu banco de dados em nuvem Firestore agora possui restaurantes que o Next.js Web App pode exibir.

Para definir o código de busca de dados, siga estas etapas:

  1. No arquivo src/app/page.js , encontre o componente <Home /> servidor e revise a chamada para a função getRestaurants , que recupera uma lista de restaurantes no tempo de execução do servidor. Você implementa a função getRestaurants nas etapas a seguir.
  2. No arquivo src/lib/firebase/firestore.js , substitua as funções applyQueryFilters e getRestaurants com o seguinte código:
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(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(),
                };
        });
}
  1. Atualize o aplicativo da web. As imagens de restaurantes aparecem como azulejos na página.

Verifique se as listagens de restaurantes carregam no horário de execução do servidor

Usando a estrutura Next.js, pode não ser óbvio quando os dados são carregados no tempo de execução do servidor ou no tempo de execução do lado do cliente.

Para verificar se as listagens de restaurantes são carregadas no tempo de execução do servidor, siga estas etapas:

  1. No aplicativo da web, abra o DevTools e desative JavaScript .

Desative JavaScipp em Devtools

  1. Atualize o aplicativo da web. As listagens de restaurantes ainda carregam. As informações do restaurante são retornadas na resposta do servidor. Quando o JavaScript está ativado, as informações do restaurante são hidratadas através do código JavaScript do lado do cliente.
  2. Em Devtools, reencenam JavaScript .

Ouça atualizações de restaurantes com os ouvintes de instantâneos em nuvem Firestore

Na seção anterior, você viu como o conjunto inicial de restaurantes carregados no arquivo src/app/page.js . O arquivo src/app/page.js é um componente do servidor e é renderizado no servidor, incluindo o código de busca de dados do Firebase.

O arquivo src/components/RestaurantListings.jsx é um componente do cliente e pode ser configurado para hidratar a marcação renderizada pelo servidor.

Para configurar o arquivo src/components/RestaurantListings.jsx para hidratar a marcação renderizada pelo servidor, siga estas etapas:

  1. No arquivo src/components/RestaurantListings.jsx , observe o seguinte código, que já está escrito para você:
useEffect(() => {
        const unsubscribe = getRestaurantsSnapshot(data => {
                setRestaurants(data);
        }, filters);

        return () => {
                unsubscribe();
        };
}, [filters]);

Esse código chama a função getRestaurantsSnapshot() , que é semelhante à função getRestaurants() que você implementou em uma etapa anterior. No entanto, essa função de instantâneo fornece um mecanismo de retorno de chamada para que o retorno de chamada seja invocado toda vez que uma alteração é feita na coleção do restaurante.

  1. No arquivo src/lib/firebase/firestore.js , substitua a função getRestaurantsSnapshot() pelo seguinte código:
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;
}

As alterações feitas na página do banco de dados Firestore agora refletem no aplicativo da web em tempo real.

  1. No aplicativo da web, selecione 27ca5d1e8ed8adfe.png > Adicione amostra de restaurantes . Se a sua função de instantâneo for implementada corretamente, os restaurantes aparecerão em tempo real sem uma atualização de página.

8. Salve os dados do usuário do aplicativo da web

  1. No arquivo src/lib/firebase/firestore.js , substitua a função updateWithRating() pelo seguinte código:
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()),
        });
};

Este código insere um novo documento do Firestore que representa a nova revisão. O código também atualiza o documento Firestore existente que representa o restaurante com números atualizados para o número de classificações e a classificação média calculada.

  1. Substitua a função addReviewToRestaurant() pelo seguinte código:
export async function addReviewToRestaurant(db, restaurantId, review) {
        if (!restaurantId) {
                throw new Error("No restaurant ID was 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`)
                );

                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;
        }
}

Implementar uma ação do servidor Next.js

Uma ação do servidor Next.js fornece uma API conveniente para acessar dados do formulário, como data.get("text") para obter o valor do texto da carga útil de envio do formulário.

Para usar uma ação Next.JS Server para processar o envio do formulário de revisão, siga estas etapas:

  1. No arquivo src/components/ReviewDialog.jsx , encontre o atributo action no elemento <form> .
<form action={handleReviewFormSubmission}>

O valor do atributo action refere -se a uma função que você implementa na próxima etapa.

  1. No arquivo src/app/actions.js , substitua a função handleReviewFormSubmission() pelo seguinte código:
// 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"),
        });
}

Adicione críticas para um restaurante

Você implementou o suporte para envios de revisão, então agora pode verificar se suas análises são inseridas no Firestore da nuvem corretamente.

Para adicionar uma revisão e verificar se ela é inserida no Cloud Firestore, siga estas etapas:

  1. No aplicativo da web, selecione um restaurante na página inicial.
  2. Na página do restaurante, clique 3e19beef78bb0d0e.png .
  3. Selecione uma classificação em estrela.
  4. Escreva uma crítica.
  5. Clique em Enviar . Sua revisão aparece no topo da lista de críticas.
  6. No Cloud Firestore, pesquise no painel Adicionar documento para o documento do restaurante que você revisou e selecione -o.
  7. No painel Start Collection , selecione classificações .
  8. No painel Adicionar documento , encontre o documento para sua revisão para verificar se ele foi inserido conforme o esperado.

Documentos no Emulador de Firestore

9. Salvar arquivos utilizados pelo usuário no aplicativo da web

Nesta seção, você adiciona funcionalidade para poder substituir a imagem associada a um restaurante quando estiver conectado. Você carrega a imagem para o armazenamento da Base Fire e atualiza o URL da imagem no documento Cloud Firestore que representa o restaurante.

Para salvar arquivos utilizados pelo usuário no aplicativo da web, siga estas etapas:

  1. No arquivo src/components/Restaurant.jsx , observe o código que é executado quando o usuário enviar um arquivo:
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 });
}

Não são necessárias alterações, mas você implementa o comportamento da função updateRestaurantImage() nas etapas a seguir.

  1. No arquivo src/lib/firebase/storage.js , substitua as funções updateRestaurantImage() e uploadImage() com o seguinte código:
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);
}

A função updateRestaurantImageReference() já está implementada para você. Esta função atualiza um documento de restaurante existente no Cloud Firestore com um URL de imagem atualizado.

Verifique a funcionalidade da imagem de imagem

Para verificar se a imagem é enviada como esperado, siga estas etapas:

  1. No aplicativo da web, verifique se você está conectado e selecione um restaurante.
  2. Clique 7067EB41FEA41FF0.PNG e carregue uma imagem do seu sistema de arquivos. Sua imagem deixa seu ambiente local e é carregado para armazenamento em nuvem. A imagem aparece imediatamente após você carregá -la.
  3. Navegue até o armazenamento em nuvem para o FireBase.
  4. Navegue até a pasta que representa o restaurante. A imagem que você carregou existe na pasta.

6CF3F9E2303C931C.PNG

10. Conclusão

Parabéns! Você aprendeu a usar o FireBase para adicionar recursos e funcionalidade a um aplicativo Next.js. Especificamente, você usou o seguinte:

Saber mais