Consumindo API GraphQL em React.jscom Apollo 클라이언트
85914 단어 reactgraphqlapolloclient
Para seguir com esse tutorial,énecessário noçes de GraphQL,além de React.js.Para se는 com GraphQL, veja o seguinte artigo를 잘 알고 있습니다.
📝 GraphQL: O que é e como usar
Se quiser ver o primeiro tutorial de como montar uma API GraphQL,veja o seguinte artigo:
📝 Montando API GraphQL em Node.js com Apollo e MongoDB
Vocêpode acompanhar o tutorial passo-a-passo ou clonar o repositório completo do GitHub.
Além disso eu disponilizei uma versão online(sem mutations para que não haja mudança nos dados online)a título de exemplo do resultado final da API.
항목 링크:
Código no GitHub:github.com/emerson-pereira/frutas
Versão online da API:graphql-frutas.herokuapp.com
Vers ão 온라인 애플리케이션 React: codesandbox.io/s/graphql-frutas-4isf8
제안
제안 사이트 sobre frutas onde podemos gerenciar os dados fazendo as opera öes CRUD.O 현장 seráfeito em 반응.js e o servidor em 노드.js.Nesse 자습서 desenvolveremos o frontend em React.js.
O 스택
프런트엔드 없음, teremos:
Apollo Client for React.jspara consumir dados da API GraphQL em React.js
Iniciando 응용 프로그램 반응회사 명
Aqui devemos continuar dentro da pasta
fruits
de onde começamos no tutorial front.Dentro dela, o seguinte comando 단락 실행iniciar um projeto react:npx create-react-app frontend
Quando terminado o processo,uma pastafrontend
terásido criada com a aplicaão inicial React.js:📦fruits
┣ 📂backend
┣ 📂frontend
┃ ┣ …
Abra um terminal de comandos e navegue para a pastafruits/frontend
.수행자 기능 확인:npm start
Deveráabrir a tela inicial gerada com create react app na porta 3000:http://localhost:3000
Aplicaão iniciada!
Antes de come çarmos,ferramenta create react 응용 프로그램cria alguns arquivos que n ão Neces á rios aqui,como arquivos de teste configura ço de service worker.Apague todos esses arquivos,atéficar com a seguinte estrutura:
📂frontend
┣ 📂public
┃ ┣ 📜favicon.ico
┃ ┣ 📜index.html
┣ 📂src
┃ ┣ 📜App.css
┃ ┣ 📜App.js
┃ ┣ 📜index.css
┃ ┣ 📜index.js
┣ 📜.gitignore
┣ 📜package.json
┗ 📜README.md
Agora vamos“limpar”alguns arquivos removendo algumas chamadas e demais coisas desnecesárias.Começando na 파스타
public
, abraindex.html
e deixe dessa maneira:카미니오:
frontend/public/index.html
<!DOCTYPE html>
<html lang="pt-BR">
<head>
<meta charset="utf-8" />
<link rel="icon" href="%PUBLIC_URL%/favicon.ico" />
<meta
name="viewport"
content="width=device-width, initial-scale=1"
/>
<meta
name="description"
content="Um app sobre informações nutricionais de frutas."
/>
<title>Frutas</title>
</head>
<body>
<noscript>
You need to enable JavaScript to run this app.
</noscript>
<div id="root"></div>
</body>
</html>
Agora,vamos adicionar os estilos que serão usado nesta aplicaão.Na pastasrc
,substitua os conteúdos deindex.css
eApp.css
com os seguintes conteúdos:카미니오:
frontend/src/index.css
body {
margin: 0;
font-family: -apple-system, BlinkMacSystemFont, "Segoe UI",
"Roboto", "Oxygen", "Ubuntu", "Cantarell", "Fira Sans",
"Droid Sans", "Helvetica Neue", sans-serif;
-webkit-font-smoothing: antialiased;
-moz-osx-font-smoothing: grayscale;
}
input,
button {
padding: 10px;
font-size: calc(10px + 1vmin);
}
button:hover {
cursor: pointer;
}
ul {
list-style: none;
margin: 20px 0;
padding: 0;
}
li {
display: flex;
justify-content: space-between;
align-items: baseline;
padding: 10px;
margin: 10px;
}
카미니오: frontend/src/App.css
.App {
text-align: center;
}
.App-header {
background-color: #282c34;
color: white;
position: absolute;
top: 10%;
right: 0;
width: 100vw;
}
.App-header h1 {
margin: 0;
padding: 20px;
}
.App-body {
background-color: #282c34;
min-height: 100vh;
display: flex;
flex-direction: column;
align-items: center;
justify-content: center;
font-size: calc(10px + 2vmin);
color: white;
}
.App-viewbox {
position: relative;
}
.App-close-btn {
position: absolute;
top: -100px;
right: -100px;
}
.App-close-btn button {
background: none;
border: 0;
color: white;
font-size: calc(10px + 2vmin);
}
.App-btn {
max-width: 120px;
width: 100%;
}
.App-btn.secondary {
background: transparent;
border: 2px solid white;
color: white;
}
.App-item-actions {
margin-left: 40px;
}
.App-item-actions a {
margin: 0 10px;
background: none;
text-decoration: none;
}
.App-item-actions a:hover {
cursor: pointer;
}
Estilos adicionados.Agora vamos a 파스타index.js
dentro desrc
e certificar que o arquivo est á como a seguir:카미니오:
frontend/src/index.js
import React from "react"
import ReactDOM from "react-dom"
import "./index.css"
import App from "./App"
ReactDOM.render(
<React.StrictMode>
<App />
</React.StrictMode>,
document.getElementById("root")
)
E agora,oúltimo arquivo a ser checado antes de começarmos com a aplicaço.Deixesrc/App.js
da seguinte maneira:카미니오:
frontend/src/App.js
import React from "react"
import "./App.css"
function App() {
return (
<div className="App">
<div className="App-header">
<h1>Frutas</h1>
</div>
<div className="App-body"></div>
</div>
)
}
export default App
Agora salve tudo e abra no navegador,certifique que não háerros no console.Deveráaparecer dessa forma:Assim,concluímos a configuraço inicial do projeto,vamos agora ao próximo passo.
구성 및 회전
Para facilitar a navegaço entre rotas,vamos usar a bibliotécaReact router.Instale-a com o comando:
npm i react-router-dom
Dentro da pastasrc
crie um arquivo chamadoroutes.js
e inicie as rotas dessa maneira:카미니오:
frontend/src/routes.js
import React from "react"
import {
BrowserRouter as Router,
Switch,
Route,
} from "react-router-dom"
import Fruits from "./components/Fruits"
const Routes = () => (
<Router>
<Switch>
<Route exact path="/">
<Fruits />
</Route>
</Switch>
</Router>
)
export default Routes
A propriedadepath
indica em qual caminho da aplicaão aquele componente seráexibido,no caso deFruits
,este seráexibido na home da aplicaão.Agora,vamos criar o componente
Fruits.js
que estásendo chamando no arquivo de rotas.Esse componente mostraráuma lista de frutas assim como as aões de exibir,editar e excluir de cada fruta.Dentro de
src
, crie uma 파스타components
.Dentro desta,crie o componente de frutas:카미니오:
frontend/src/components/Fruits.js
import React from "react"
import { Link } from "react-router-dom"
const FruitsList = () => {
return (
<>
<ul>
<li>
<span>Banana</span>
<div className="App-item-actions">
<Link>
<span role="img" aria-label="visualizar">
👀
</span>
</Link>
<Link>
<span role="img" aria-label="editar">
✏️
</span>
</Link>
<Link>
<span role="img" aria-label="excluir">
❌
</span>
</Link>
</div>
</li>
</ul>
<p>
<Link>
<button>Nova Fruta</button>
</Link>
</p>
</>
)
}
export default FruitsList
Por enquanto adicionamos uma lista com apenas uma fruta.Também criamos
Link
ao redor dos botões,mas não apontamos para nenhuma rota,nesse momento.Faremos isso Mai는 친구입니다.Agora,váaté
App.js
e inclua a rota criada:카미니오:
frontend/src/App.js
import React from "react"
import "./App.css"
import Routes from "./routes"
function App() {
return (
<div className="App">
<div className="App-header">
<h1>Frutas</h1>
</div>
<div className="App-body">
<Routes /> </div>
</div>
)
}
export default App
인증서 a lista de frutas criada aparece na tela inicial da aplica ão.Agora,o próximo passo:
ConectandoáAPI GraphQL com Apollo
Vamos come çar instalando는 deped ências para usar apollo 고객입니다.
주: Aqui estamos usando apollo 고객 navers ão 3.
npm i @apollo/client graphql
@ 아폴로/고객: Pacote apollo com o Necessario para usar apollo 고객
graphql: Pacote OFFICIAL do graphql com a l ógica para parsear 조회
카미니오:
frontend/src/App.js
import React from "react"
import { ApolloProvider, ApolloClient, InMemoryCache,} from "@apollo/client"import "./App.css"
import Routes from "./routes"
const client = new ApolloClient({ uri: "http://localhost:4000", cache: new InMemoryCache(),})
function App() {
return (
<ApolloProvider client={client}> <div className="App">
<div className="App-header">
<h1>Frutas</h1>
</div>
<div className="App-body">
<Routes />
</div>
</div>
</ApolloProvider> )
}
export default App
Agora vamos voltar ao componenteFruits.js
e popular o componente com dados vindos da API usando Apollo client.카미니오:
frontend/src/components/Fruits.js
import React from "react"
import { gql, useQuery } from "@apollo/client"import { Link } from "react-router-dom"
export const GET_FRUITS = gql` { fruits { id name } }`
const FruitsList = () => {
const { loading, error, data } = useQuery(GET_FRUITS) if (loading) return <p>Loading...</p> if (error) return <p>Error :(</p>
return (
<>
<ul>
{data.fruits && data.fruits.map(({ name, id }) => ( <li key={id}> <span>{name}</span> <div className="App-item-actions"> <Link to={`/fruit/${id}`}> <span role="img" aria-label="visualizar"> 👀 </span> </Link> <Link to={`/editFruit/${id}`}> <span role="img" aria-label="editar"> ✏️ </span> </Link> <Link to={`/deleteFruit/${id}`}> <span role="img" aria-label="excluir"> ❌ </span> </Link> </div> </li> ))} </ul>
<p>
<Link to="/createFruit"> <button>Nova Fruta</button>
</Link>
</p>
</>
)
}
export default FruitsList
E simples assim,fizemos a query E populmos o component E com dados da API.Ainda fizemos um Returno simples ao usuário com feedback de loading e de erro,caso ocorra algum.Além disso,de antemão,apontamos rotas para cadaãoCRUDrelacionadaáfrutas.Vamos、agora、criar os components para cada aço para deposis conectar cada rotaáseu respectivo component.
법은 일찍이 때가 많이 쌓였다
Para seguir a ordem do acrônimo,vamos começar com o component de criaço:
창조
카미니오:
frontend/src/components/CreateFruit.js
import React from "react"
import { gql, useMutation } from "@apollo/client"
import { Link, useHistory } from "react-router-dom"
import { GET_FRUITS } from "./Fruits"
const CREATE_FRUIT = gql`
mutation UpdateFruit(
$name: String!
$sugar: String!
$calories: String!
) {
createFruit(
fruit: {
name: $name
nutritions: { sugar: $sugar, calories: $calories }
}
) {
id
name
nutritions {
calories
sugar
}
}
}
`
const CreateFruit = () => {
const history = useHistory()
const [createFruit, { loading, error }] = useMutation(
CREATE_FRUIT,
{
update(cache, { data: { createFruit } }) {
const { fruits } = cache.readQuery({ query: GET_FRUITS })
cache.writeQuery({
query: GET_FRUITS,
data: { fruits: fruits.concat([createFruit]) },
})
},
onCompleted() {
history.push(`/`)
},
}
)
if (loading) return <p>Loading...</p>
if (error) return <p>Error :(</p>
let nameInput
let sugarInput
let caloriesInput
return (
<div>
<form
className="App-viewbox"
onSubmit={e => {
e.preventDefault()
createFruit({
variables: {
name: nameInput.value,
sugar: sugarInput.value,
calories: caloriesInput.value,
},
})
nameInput.value = ""
sugarInput.value = ""
caloriesInput.value = ""
}}
>
<p>
<label>
Fruta
<br />
<input
type="text"
name="name"
ref={node => {
nameInput = node
}}
/>
</label>
</p>
<p>
<label>
Açucar (g)
<br />
<input
type="text"
name="sugar"
ref={node => {
sugarInput = node
}}
/>
</label>
</p>
<p>
<label>
Calorias
<br />
<input
type="text"
name="calories"
ref={node => {
caloriesInput = node
}}
/>
</label>
</p>
<p className="App-close-btn">
<Link to="/">
<button>✖</button>
</Link>
</p>
<p>
<button className="App-btn" type="submit">
Salvar
</button>
</p>
</form>
</div>
)
}
export default CreateFruit
Neste componente criamosuma fruta usando 돌연변이, e atualizamoso cache do Apollo reutilizando a queryGET_FRUITS
exposta emFruits.js
.Para entender mais sobre esse assunto 영사관 adocumentação do Apollo client sobre mutations.Além disso,também tomamos vantagem do método
onCompleted
para redirecionar a página para home deposis deposis de criar a fruta.읽다
Agora,criaremos o componente de Visualizao.
카미니오:
frontend/src/components/Fruit.js
import React from "react"
import { gql, useQuery } from "@apollo/client"
import { useParams, Link } from "react-router-dom"
export const GET_FRUIT_BY_ID = gql`
query GetFruit($id: ID!) {
fruit(id: $id) {
id
name
nutritions {
sugar
calories
}
}
}
`
const Fruit = () => {
const { id } = useParams()
const { loading, error, data } = useQuery(GET_FRUIT_BY_ID, {
variables: { id },
})
if (loading) return <p>Loading...</p>
if (error) return <p>Error :(</p>
return (
<div className="App-viewbox">
<p>
<strong>Fruta: </strong>
{data.fruit.name}
</p>
<p>
<strong>Açucar: </strong>
{data.fruit.nutritions.sugar}g
</p>
<p>
<strong>Calorias: </strong>
{data.fruit.nutritions.calories}kcal
</p>
<p className="App-close-btn">
<Link to="/">
<button>✖</button>
</Link>
</p>
<p>
<Link to={`/editFruit/${id}`}>
<button>Editar</button>
</Link>
</p>
</div>
)
}
export default Fruit
Aqui a operaãoébem simples e passamos aid
da fruta pela URL da rota usandouseParams
do React router.현대화하다
E, o 섹션:
카미니오:
frontend/src/components/EditFruit.js
import React from "react"
import { gql, useQuery, useMutation } from "@apollo/client"
import { useParams, Link, useHistory } from "react-router-dom"
import { GET_FRUIT_BY_ID } from "./Fruit"
const UPDATE_FRUIT = gql`
mutation UpdateFruit(
$id: String!
$name: String
$sugar: String
$calories: String
) {
updateFruit(
id: $id
fruit: {
name: $name
nutritions: { sugar: $sugar, calories: $calories }
}
) {
id
name
nutritions {
calories
sugar
}
}
}
`
const EditFruit = () => {
const { id } = useParams()
const history = useHistory()
const { loading, error, data } = useQuery(GET_FRUIT_BY_ID, {
variables: { id },
})
const [updateFruit, { error: mutationError }] = useMutation(
UPDATE_FRUIT,
{
onCompleted() {
history.push(`/`)
},
}
)
if (loading) return <p>Loading...</p>
if (error || mutationError) return <p>Error :(</p>
let nameInput
let sugarInput
let caloriesInput
return (
<div>
<form
className="App-viewbox"
onSubmit={e => {
e.preventDefault()
updateFruit({
variables: {
id: data.fruit.id,
name: nameInput.value,
sugar: sugarInput.value,
calories: caloriesInput.value,
},
})
}}
>
<p>
<label>
Fruta
<br />
<input
type="text"
name="name"
defaultValue={data.fruit.name}
ref={node => {
nameInput = node
}}
/>
</label>
</p>
<p>
<label>
Açucar (g)
<br />
<input
type="text"
name="sugar"
defaultValue={data.fruit.nutritions.sugar}
ref={node => {
sugarInput = node
}}
/>
</label>
</p>
<p>
<label>
Calorias
<br />
<input
type="text"
name="calories"
defaultValue={data.fruit.nutritions.calories}
ref={node => {
caloriesInput = node
}}
/>
</label>
</p>
<p className="App-close-btn">
<Link to="/">
<button type="button">✖</button>
</Link>
</p>
<p>
<button className="App-btn" type="submit">
Salvar
</button>
</p>
</form>
</div>
)
}
export default EditFruit
Aqui também usamos par–metro vindo da rota para Identificationcarid
da fruta e redirecionamos para home depois de finalizado.Assim como usamos a queryGET_FRUIT_BY_ID
importada do component de visualizaão.삭제하다
E、 pra finalizar,criaremos o componente de deleção de fruta.
카미니오:
frontend/src/components/DeleteFruit.js
import React from "react"
import { gql, useQuery, useMutation } from "@apollo/client"
import { useParams, Link, useHistory } from "react-router-dom"
import { GET_FRUITS } from "./Fruits"
import { GET_FRUIT_BY_ID } from "./Fruit"
const DELETE_FRUIT = gql`
mutation DeleteFruit($id: String) {
deleteFruit(id: $id) {
id
name
nutritions {
calories
sugar
}
}
}
`
const DeleteFruit = () => {
const history = useHistory()
const { id } = useParams()
const { loading, error, data } = useQuery(GET_FRUIT_BY_ID, {
variables: { id },
})
const [deleteFruit, { error: mutationError }] = useMutation(
DELETE_FRUIT,
{
update(cache) {
const { fruits } = cache.readQuery({ query: GET_FRUITS })
const deletedIndex = fruits.findIndex(
fruit => fruit.id === id
)
const updatedCache = [
...fruits.slice(0, deletedIndex),
...fruits.slice(deletedIndex + 1, fruits.length),
]
cache.writeQuery({
query: GET_FRUITS,
data: {
fruits: updatedCache,
},
})
},
onCompleted() {
history.push(`/`)
},
}
)
if (loading) return <p>Loading...</p>
if (error || mutationError) return <p>Error :(</p>
return (
<div>
<form
className="App-viewbox"
onSubmit={e => {
e.preventDefault()
deleteFruit({
variables: { id },
})
}}
>
<p>
Excluir <strong>{data.fruit.name}</strong>?
</p>
<p className="App-close-btn">
<Link to="/">
<button>✖</button>
</Link>
</p>
<p>
<button className="App-btn" type="submit">
Excluir
</button>
</p>
</form>
</div>
)
}
export default DeleteFruit
Aqui també mé manipulado cache do Apollo 클라이언트.deposis de removido o item,removemos o mesmo item do cache e relacionamos a queryGET_FRUITS
com os dados atualizados.Crud feito com 성공!
Não deixe de consultar a documentaço office do Apollo Cliente para maiores detalhes:
🔗 www.apollographql.com/docs/react
리칸토로타
Agora para finalizar,ligamos cada rotaáseu componente.
카미니오:
frontend/src/routes.js
import React from "react"
import {
BrowserRouter as Router,
Switch,
Route,
} from "react-router-dom"
import Fruits from "./components/Fruits"
import Fruit from "./components/Fruit"import CreateFruit from "./components/CreateFruit"import EditFruit from "./components/EditFruit"import DeleteFruit from "./components/DeleteFruit"
const Routes = () => (
<Router>
<Switch>
<Route exact path="/">
<Fruits />
</Route>
<Route path="/fruit/:id"> <Fruit /> </Route> <Route path="/createFruit"> <CreateFruit /> </Route> <Route path="/editFruit/:id"> <EditFruit /> </Route> <Route path="/deleteFruit/:id"> <DeleteFruit /> </Route> </Switch>
</Router>
)
export default Routes
결론
E esse foi o tutorial,nesta jornada vocêaprendeu:
항목 링크:
Código no GitHub:github.com/emerson-pereira/frutas
Versão online da API:graphql-frutas.herokuapp.com
Vers ão 온라인 애플리케이션 React: codesandbox.io/s/graphql-frutas-4isf8
Reference
이 문제에 관하여(Consumindo API GraphQL em React.jscom Apollo 클라이언트), 우리는 이곳에서 더 많은 자료를 발견하고 링크를 클릭하여 보았다 https://dev.to/emersonpereira/consumindo-api-graphql-em-react-js-com-apollo-client-13in텍스트를 자유롭게 공유하거나 복사할 수 있습니다.하지만 이 문서의 URL은 참조 URL로 남겨 두십시오.
우수한 개발자 콘텐츠 발견에 전념 (Collection and Share based on the CC Protocol.)