O terceiro de três artigos focados na criação de React Fullstack e GraphQL com o Apollo GraphQL Client.
- Configuração de um servidor NoSQL Couchbase (Parte 1)
- Criação de uma API Express-GraphQL (Parte 2)
- Criar um cliente Apollo GraphQL em React (Parte 3)
- Código-fonte final
Criação do aplicativo React com um cliente Apollo GraphQL
Neste segmento do tutorial, eu o ajudarei a conectar as partes relacionadas ao uso do Apollo GraphQL. Incluí a maior parte do aplicativo React de que você precisará em um repositório do GitHub. Esse código predefinido que clonamos em nosso projeto será um projeto React que foi criado com o Create Rect App e tem roteamento, navegação, menus, comportamento responsivo, estado e contexto sendo gerenciados, bem como alguns utilitários e outros componentes para dar suporte a uma arquitetura básica de aplicativo. Eu queria ter certeza de que só precisaríamos nos preocupar com a configuração do cliente Apollo GraphQL, mas queria fazer isso no contexto de um aplicativo em funcionamento.
Clonar um aplicativo React existente
Nosso front-end React desacoplado será um irmão do servidor couchbase-gql
Aqui está uma ideia básica de como será a nossa estrutura de diretórios:
1 2 3 4 5 |
raiva-com-couchbase │ └───couchbase-gql-servidor │ └───reagir-apolo-cliente |
Vamos clonar o ponto de partida do nosso projeto React executando o seguinte comando git a partir da raiz (raiva com base de toque
) em nosso terminal:
1 |
git clone https://github.com/httpJunkie/reagir-apolo-cliente.git && cd reagir-apolo-cliente && rm -rf .git |
No comando acima, removemos o .git
já que não queremos levar o histórico do git existente do projeto que clonamos para o nosso projeto. Você precisará inicializar o git por conta própria e fazer o commit periodicamente, se quiser. Isso é incentivado para que você não perca seu trabalho.
Agora temos um aplicativo React em funcionamento adicionado ao nosso projeto com roteamento básico. Há alguns componentes e utilitários que existem no projeto React, mas ainda não estão conectados. Antes de chegarmos a eles, vamos executar o aplicativo React por conta própria para garantir que tudo esteja funcionando sem erros:
1 |
npm instalar && npm iniciar |
Abra o console (⌘ Cmd + ⌥ Option + I no Mac) (Ctrl + ↑ Shift + J no PC)
Certifique-se de que clicar para frente e para trás de Home para Airlines não gere nenhum erro e que não haja erros ou avisos importantes. O que vemos nesta visualização é a rota Airlines, que é a rota à qual adicionaremos nosso recurso de detalhes mestre. É como se outra pessoa já tivesse se encarregado de todo o estilo e do layout básico, nosso trabalho será conectar o lista de companhias aéreas.jsx
e detalhes da companhia aérea.jsx
no lugar do texto atual do espaço reservado em cada lado da página. Felizmente, nossa equipe de design garantiu que todo o trabalho de layout e CSS estivesse completo!
Antes de fazermos alterações no aplicativo React, vamos entender alguns dos arquivos que temos em nosso projeto e que ainda não estão em jogo com nossa rota Airline.
Visão geral de nossos ativos
Há seis arquivos com os quais queremos nos familiarizar e que estão aguardando para serem usados.
- hoc/withApolloProvider.js
- partial/airline-list.jsx
- partial/airline-details.jsx
- utility/pagination.jsx
- utility/pagination.scss
- routes/airline-gql.js
Uma convenção que estamos usando em relação à estrutura de diretórios é que os componentes no diretório "rotas
" são componentes do React que são resolvidos para formar uma rota específica e esses arquivos dentro do diretório "parcial
" são componentes que não são uma visualização carregada por uma rota, mas sim uma visualização parcial ou um componente que pode ser potencialmente reutilizado em nosso aplicativo. Essa é uma convenção que eu uso, e não algo que o React nos obriga a fazer.
comApolloProvider - Estou usando um componente de ordem superior para facilitar a leitura. Entenda que isso é semelhante a importar o ApolloProvider em um componente pai. Essa pode não ser a melhor prática, mas gosto do fato de manter meu código organizado.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 |
importação Reagir de 'react' importação { ApolloProvider, InMemoryCache, ApolloClient } de '@apollo/client'; const comApolloProvider = (WrappedComponent, graphqlEndpoint) => { const apolloClient = novo ApolloClient({ uri: graphqlEndpoint, cache: novo InMemoryCache() }) retorno (adereços) => ( <ApolloProvider cliente={apolloClient}> <WrappedComponent {...adereços} wrappedBy={"withApolloProvider"} /> </ApolloProvider> ) } exportação padrão comApolloProvider |
Temos lista de companhias aéreas.jsx
e um detalhes da companhia aérea.jsx
esses dois componentes serão carregados lado a lado em nosso companhias aéreas.jsx
componente. A lista simplesmente exibirá cada companhia aérea e usará paginação.jsx
para garantir que não tenhamos uma longa lista no lado esquerdo da página.
Por fim, temos o companhia aérea-gql.js
que é simplesmente nosso arquivo Consulta GraphQL para todas as companhias aéreas do Reino Unido. Eu gosto de separar minhas consultas em outro arquivo para fins de organização, não é necessário, mas limpa o companhias aéreas.jsx
arquivo.
Como funciona nossa página mestre-detalhe
Em nosso projeto, temos uma relação de componente mestre-detalhe (lista de companhias aéreas.jsx
&& detalhes da companhia aérea.jsx
), no /companhias aéreas
rota. Essa rota é resolvida para um componente de visualização chamado: companhias aéreas.jsx
que utiliza os recursos do React Router para corresponder não apenas à rota, mas também a um parâmetro URI adicional (companhia aéreaId
) que podemos anexar ao final da rota para sermos específicos. Quando nenhuma rota específica companhia aéreaId
O parâmetro URI está presente no URL:
http://localhost:3000/airlines
Ele exibirá apenas uma lista de companhias aéreas no lado esquerdo. Além disso, será exibido um link no lado direito da página com os seguintes dizeres: "Selecione uma companhia aérea".
A seleção de uma companhia aérea no menu carregará os detalhes no lado direito da página. Depois de clicado, atualizaremos o URL com o ID adequado usando um componente fornecido pelo React Router:
http://localhost:3000/airlines/1355
Aqui, faremos a correspondência com o ID 1355
com a companhia aérea correta já na memória em nossos dados do aplicativo React e exibir as informações apropriadas da companhia aérea "British Airways".
Adição de dependências para nosso cliente Apollo GraphQL
Precisamos de três pacotes: @apollo/react-hooks
, apollo-boost
e graphql
, trazidos para o projeto, então vamos cd
no cliente react-apollo
e execute o comando npm install
para os pacotes necessários para o GraphQL e o Apollo:
1 |
npm instalar @apolo/cliente graphql |
Se você quiser se familiarizar com o Apollo e o GraphQL, o Documentação do GraphQL para consultasO site da empresa, que é um lugar ideal para começar, também pode ser visto: Documentação do GraphQL sobre como fazer consultas no Apollo e no React.
Criação da página mestre-detalhe
O companhias aéreas.jsx
é onde faremos a maior parte do nosso trabalho. Vamos começar adicionando algumas importações:
1 2 |
importação { useQuery } de '@apollo/client' importação { companhia aéreaGql } de './airline-gql' |
Sob o importar { airlineGql }
precisamos importar a linha comApolloProvider
um componente de ordem superior.
1 |
importação comApolloProvider de '../hoc/withApolloProvider' |
Isso envolve nosso componente com um provedor Apollo. Usei esse método em vez de envolver todo o nosso aplicativo com um ApolloProvider. Uma tentativa de tornar o código que estou compartilhando um pouco menos complexo. Atualizaremos o companhias aéreas.jsx
exportação do arquivo.
A linha que diz:
exportar linhas aéreas padrão
deve ser alterado para:
1 2 |
const WrappedComponent = comApolloProvider(Companhias aéreas, 'http://localhost:4000/graphql') exportação padrão WrappedComponent |
Nosso primeiro argumento para o HOC é um componente React Companhias aéreas
(este componente). Portanto, quando nosso aplicativo é renderizado, o componente <Airlines />
será envolvido por nosso componente ApolloProvider. Um provedor no React é uma função da API Context. O Context fornece dados em toda a árvore de componentes em nosso aplicativo React sem precisar passar os dados manualmente por meio de props. No nosso caso, o <Airlines />
será envolvido pelo nosso provedor, dando a ele acesso aos dados fornecidos pelo código do cliente Apollo definido nesse componente comApolloProvider
componente de ordem superior.
Nossas importações finais são os dois componentes que já criei para você (lista de companhias aéreas.jsx e detalhes da companhia aérea.jsx):
1 2 |
importação Lista de companhias aéreas de '../partial/airline-list' importação Detalhes da companhia aérea de '../partial/airline-details' |
Quando esses dois arquivos forem importados, poderemos adicionar a sintaxe de seus componentes à nossa grade flexbox (simple-flexbox que criamos para nos ajudar a dividir facilmente nossa página por uma porcentagem:
1 2 3 4 5 6 7 8 |
<Linha horizontal="espaçado"> <Coluna flexGrow={1} estilo={{ largura mínima: '280px', largura: '65%' }}> <Lista de companhias aéreas companhias aéreas={companhias aéreas} /> </Coluna> <Coluna flexGrow={1} estilo={{ largura: '45%' }}> <Detalhes da companhia aérea companhia aérea={companhia aérea} /> </Coluna> </Linha> |
Com tudo isso pronto, só precisamos lidar com nossos dados. useQuery
retorna um objeto do cliente Apollo GraphQL com carregamento
, erro
e dados
que podemos usar. Também precisamos combinar o caminho da nossa rota (a partir do URL). O acesso a isso é fácil com o React Router: (match.params
).
Vamos usar a função partida
desestruturando os props para o Companhias aéreas
Componente::
1 |
const Companhias aéreas = ({ partida }) => { |
Em seguida, adicionaremos o seguinte ao nível superior do nosso Companhias aéreas
Componente:
1 2 3 4 5 6 7 8 |
const companhia aéreaId = Número(partida.parâmetros.id) const { carregamento, erro, dados } = useQuery(companhia aéreaGql) se (carregamento) retorno <p>Carregamento...</p> Se (erro) retornar <p>Erro :( <span style="{{color:" 'red'}}>{error.message}</s>panela> )</p> const companhias aéreas = dados.companhias aéreasUK const companhia aérea = partida.parâmetros.id ? companhias aéreas.encontrar(a => a.id === companhia aéreaId) : nulo |
O que acabamos de fazer:
- Conjunto
companhia aéreaId
se omatch.params.id
retorna um número e nãoindefinido
(temos uma ID em nosso caminho de rota?/companhias aéreas/1355
ou não/companhias aéreas/
?). - Usando a string de consulta GraphQL exportada em nosso
companhia aéreaGql
file. Lembre-se de que ele retorna coisas, portanto, estamos desestruturando-as aqui também. - Retornar "loading" até que os dados tenham sido carregados
- Retornar "Error" caso nosso servidor GraphQL não esteja em execução ou tenha um erro, etc...
- Capture os dados de todas as companhias aéreas retornadas de nossa consulta em uma variável local chamada
companhias aéreas
- Se
match.params.id
contém um número, significa que nossa rota contém uma ID. Nesse caso, capturamos os dados dessa companhia aérea específica em uma variável local chamadacompanhia aérea
caso contrário, armazenamos um valor nulo nessa variável.
O partida
funcionará devido à maneira como configuramos nossa rota no App.js
página:
1 2 3 |
<Rota exato caminho={["/airlines/:id", "/airlines/"]} renderizar={(adereços) => <Companhias aéreas {...adereços} />} /> |
Essa rota, de fato, diz: Procure uma rota com o nome /companhias aéreas/
e qualquer coisa depois disso estará disponível usando o match.params.id
sintaxe.
Se executarmos nosso projeto agora e o servidor GraphQL não estiver em execução, receberemos um erro.
"Error :( Network error: Failed to fetch )"
Portanto, precisamos iniciar esse servidor antes de executar nosso aplicativo React para testar nossa página master-detail.
Executando nosso aplicativo Full Stack
Para executar nosso projeto fullstack React e GraphQL, precisaremos primeiro adicionar mais um pacote:
1 |
npm instalar cors |
Nosso aplicativo está hospedado em um domínio (localhost:3000). Ele faz solicitações a uma API em outro domínio (localhost:4000). Sem o CORS, a política de mesma origem do navegador bloqueará a solicitação.
O CORS permite que nossa API informe ao navegador que não há problema em nosso aplicativo Web fazer solicitações a ela. Ele faz isso enviando cabeçalhos HTTP. Precisamos usar o CORS em nosso servidor Express-GraphQL. Basta adicionar o código a seguir para substituir as sete primeiras linhas existentes.
1 2 3 4 5 6 7 8 9 |
const expresso = exigir("expresso) const cors = exigir('cors') const graphqlHTTP = exigir('express-graphql') const { buildSchema } = exigir('graphql') const couchbase = exigir('couchbase') const aplicativo = expresso() aplicativo.uso(cors()) |
Para se familiarizar com o CORS da frente para trás, confira um artigo intitulado: "Como ativar o CORS para o Express-GraphQL e o Apollo Server”
Neste ponto, só precisamos garantir que nossa instância do Couchbase Server esteja funcionando.
No diretório do servidor, execute o comando node para iniciar o servidor Express-GraphQL:
1 |
nó servidor |
Em seguida, no diretório do cliente, vamos executar o comando para iniciar nosso cliente React:
1 |
npm iniciar |
O aplicativo React se conecta à API Express-GraphQL, que, por sua vez, consulta o banco de dados Couchbase para recuperar os dados da companhia aérea, e agora devemos ter um aplicativo funcional se o visitarmos: localhost:3000
Usando Postinstall e Concurrently
Agora que tudo está funcionando, vamos atualizar o projeto para executar ambos os projetos com um único comando npm.
Precisamos inicializar um projeto npm em nosso diretório raiz. Tanto o servidor quanto o cliente têm seus próprios diretórios de projeto. Damos ao diretório raiz seu próprio package.json
com apenas uma dependência.
Altere os diretórios para a raiz e execute:
1 |
npm inicial -y && npm instalar ao mesmo tempo --salvar-dev |
Isso inicializará o npm e aceitará todos os padrões (caso contrário, remova o -y
) e instalar o pacote de que precisamos para executar simultaneamente os dois projetos com um único comando.
Vamos configurar dois scripts chamados cliente
e servidor
para executar cada projeto individualmente e, em seguida, um iniciar
para executar o cliente e o servidor ao mesmo tempo.
Também usaremos pós-instalação
para executar o npm install
de forma independente quando o script npm install
está completo. pós-instalação
faz parte de Scripts npm por padrão. Todas essas alterações que faremos abaixo permitirão que alguém clone seu repositório, execute npm install && npm start
que iniciará as três instalações e, em seguida, executará cada projeto simultaneamente.
Substitua o package.json
que acabou de ser adicionado com os scripts a seguir:
1 2 3 4 5 6 |
"scripts": { "cliente": "cd react-apollo-client && npm start", "servidor": "cd couchbase-gql-server && node server", "start": "concurrently --kill-others \"npm run server\" \"npm run client\"", "postinstall": "(cd couchbase-gql-server && npm install); (cd react-apollo-client && npm install);" }, |
Inicializamos o npm na raiz do nosso projeto, configuramos dois scripts para cliente
e servidor
que podemos executar simultaneamente com npm start
. Além disso, quando alguém clona nosso repositório, agora pode executar: npm install && npm start
e ele instalará todos os pacotes dos três projetos e depois os ativará, desde que eles tenham o Couchbase Server em execução, tudo funcionará.
Remover usuário e senha do arquivo do servidor
Um toque final é mover o nome de usuário e a senha de nossas credenciais de conexão com o Couchbase para um .env
arquivo. Isso garantirá que não enviemos credenciais confidenciais ao GitHub para que o mundo as veja.
Altere os diretórios para couchbase-gql-server/
e instalar dotenv
:
1 |
npm instalar dotenv --salvar-dev |
Em seguida, importe dotenv
e usar a desestruturação de objetos para obter acesso às variáveis que configuramos em nosso .env
file:
1 2 |
exigir('dotenv').configuração() const { cbUsuário, cbPass } = processo.env |
Atualize o código em que usamos o nome de usuário e a senha:
1 2 3 |
const agrupamento = novo couchbase.Aglomerado('couchbase://localhost', { nome de usuário: cbUsuário, senha: cbPass }) |
Crie um arquivo em nosso servidor couchbase-gql
diretório denominado .env
com nossas credenciais do Couchbase Server:
1 2 |
cbUsuário=Administrador cbPass=senha |
Também precisamos atualizar os diretórios do servidor .gitignore
arquivo. Há um bloco de ignorações rotulado como #misc
Vamos modificar esse bloco de ignores e adicionar .env
para ele. Lembre-se de que esse arquivo não será carregado no git como parte do controle do nosso curso.
1 2 3 4 5 6 7 |
# misc DS_Store .env .env.local .env.desenvolvimento.local .env.teste.local .env.produção.local |
Vamos executar nosso projeto a partir da raiz usando npm start
para garantir que tudo continue funcionando!
Recapitulação do projeto
Criamos um projeto fullstack de React e GraphQL. Utilizando SDK do nó do Couchbase e do cliente e servidor Apollo GraphQL, aproveitamos nosso conhecimento de JavaScript para criar um aplicativo de pilha completa. Espero que este tutorial o ajude em sua busca para dominar o JavaScript de pilha completa.
Estou disponível no Twitter @httpJunkieSe você quiser, sinta-se à vontade para entrar em contato, meu DM está sempre aberto! Confira os links fornecidos abaixo para obter mais informações sobre a criação com Apollo e React.
O código final desse projeto pode ser encontrado no GitHub em:
github.com/httpJunkie/rage-with-couchbase-final