de Howon Song

Cum să utilizați GraphQL în aplicația dvs. Redux

Cum sa utilizati GraphQL in aplicatia dvs
(credit de imagine)

Preluarea și gestionarea datelor în Redux necesită prea multă muncă. Ca Sashko Stubailo evidențiază:

Din păcate, modelele pentru încărcarea asincronă a datelor serverului într-o aplicație Redux nu sunt la fel de bine stabilite și implică adesea utilizarea bibliotecilor de asistență externe, cum ar fi redux-saga. Trebuie să scrieți cod personalizat pentru a apela punctele finale ale serverului, a interpreta datele, a le normaliza și a le introduce în magazin – totul ținând evidența diferitelor stări de eroare și de încărcare.

Până la sfârșitul acestui tutorial, veți fi învățat cum să rezolvați această problemă, permițând clientului Apollo să preia și să gestioneze datele pentru dvs. Nu va mai trebui să scrieți mai multe distribuitoare de acțiuni, reductoare și normalizatoare pentru a prelua și sincroniza date între front-end și back-end.

Dar înainte de a începe tutorialul, asigurați-vă că:

  • Știți elementele de bază ale interogărilor GraphQL – dacă sunteți complet nou în GraphQL, ar trebui să reveniți după ce ați făcut acest lucru tutorial.
  • Aveți o experiență de lucru cu React / Redux – dacă nu, ar trebui să reveniți după ce ați făcut-o tutorial de reacție și tutorial redux.

În acest tutorial, vom parcurge împreună 6 secțiuni.

  1. Configurarea mediului server (rapid)
  2. Configurarea aplicației redux boilerplate
  3. Adăugarea unui client GraphQL (client Apollo)
  4. Preluarea datelor cu interogare GraphQL
  5. Se preiau și mai multe date
  6. Pasii urmatori

1. Configurarea mediului server

În primul rând, avem nevoie de un server GraphQL. Cel mai simplu mod de a avea un server care rulează este completarea acestui minunat tutorial.

Dacă vă simțiți leneși, puteți doar să o clonați pe a mea repo, care este aproape același server pe care l-ați obține dacă ați face singur tutorialul. Serverul acceptă interogări GraphQL pentru a prelua date dintr-un DB SQLite.

Să-l rulăm și să vedem dacă funcționează corect:

$ git clone https://github.com/woniesong92/apollo-starter-kit$ cd apollo-starter-kit$ npm install$ npm start

Serverul ar trebui să ruleze la http: // localhost: 8080 / graphql. Navigați la pagina respectivă și vedeți dacă aveți o interfață GraphiQL funcțională cu rezultate de genul acesta:

1612010047 179 Cum sa utilizati GraphQL in aplicatia dvs

GraphiQL vă permite să testați diferite interogări și să vedeți imediat ce răspuns obțineți de la server. Dacă nu dorim numele de familie al unui autor și un mesaj de cookie fortune într-un răspuns, putem actualiza interogarea ca mai jos:

1612010047 517 Cum sa utilizati GraphQL in aplicatia dvs

Și exact așa ne place. Am confirmat că serverul nostru funcționează bine și returnează răspunsuri bune, așa că să începem să construim clientul.

2. Configurarea aplicației redux boilerplate

Pentru simplitate, vom folosi un redux boilerplate astfel încât să putem obține toate setările (de exemplu, Babel, webpack, CSS etc.) gratuit. Îmi place această boilerplate, deoarece configurarea sa este ușor de urmărit și este doar de partea clientului – ceea ce îl face perfect pentru acest tutorial.

$ git clone https://github.com/woniesong92/react-redux-starter-kit.git$ cd react-redux-starter-kit$ npm install$ npm start

Să navigăm la http: // localhost: 3000 / pentru a vedea dacă serverul client rulează.

1612010048 351 Cum sa utilizati GraphQL in aplicatia dvs

Ura! Clientul rulează. Este timpul să începem să adăugăm un client GraphQL. Din nou, obiectivul nostru este să preluăm cu ușurință date de pe server și să le redăm în pagina de destinație (HomeView) fără prea mult efort, utilizând interogări GraphQL.

3. Adăugarea unui client GraphQL (Apollo Client)

Instalați pachetele apollo-client, react-apollo și graphql-tag.

$ npm install apollo-client react-apollo graphql-tag --save

Apoi, deschideți fișierul src / containers / AppContainer.js, rădăcina aplicației noastre Redux. Aici trecem magazinul redux la componentele copil, folosind Provider din react-redux.

import React, { PropTypes } from 'react'import { Router } from 'react-router'import { Provider } from 'react-redux'
class AppContainer extends React.Component {  static propTypes = {    history: PropTypes.object.isRequired,    routes: PropTypes.object.isRequired,    routerKey: PropTypes.number,    store: PropTypes.object.isRequired  }
render () {    const { history, routes, routerKey, store } = this.props
return (      <Provider store={store}>        <div>          <Router history={history} children={routes} key={routerKey} />        </div>      </Provider>    )  }}
export default AppContainer

Trebuie să inițializăm un ApolloClient și să înlocuim furnizorul din react-redux cu ApolloProvider din react-apollo.

import React, { Component, PropTypes } from 'react'import { Router } from 'react-router'import ApolloClient, { createNetworkInterface, addTypename } from 'apollo-client'import { ApolloProvider } from 'react-apollo'
const client = new ApolloClient({  networkInterface: createNetworkInterface('http://localhost:8080/graphql'),  queryTransformer: addTypename,})
class AppContainer extends Component {  static propTypes = {    history: PropTypes.object.isRequired,    routes: PropTypes.object.isRequired,    store: PropTypes.object.isRequired  }
render () {    const { history, routes } = this.props
return (      <ApolloProvider client={client}>        <div>          <Router history={history} children={routes} />        </div>      </ApolloProvider>    )  }}
export default AppContainer

Asta este! Tocmai am adăugat un client GraphQL la o aplicație simplă Redux, cu ușurință.

Să mergem mai departe și să încercăm prima noastră interogare GraphQL.

4. Preluarea datelor cu interogări GraphQL

Deschideți src / views / HomeView.js

import React from 'react'import { connect } from 'react-redux'import { bindActionCreators } from 'redux'
export class HomeView extends React.Component {  constructor(props) {    super(props)  }
render () {    return (      <div className="home">        <h1>Hello World</h1>      </div>    )  }}
// This is where you usually retrieve the data stored in the redux store (e.g posts: state.posts.data)const mapStateToProps = (state, { params }) => ({
})
// This is where you usually bind dispatch to actions that are used to request data from the backend. You will call the dispatcher in componentDidMount.const mapDispatchToProps = (dispatch) => {  const actions = {}
  return {    actions: bindActionCreators(actions, dispatch)  }}
export default connect(  mapStateToProps,  mapDispatchToProps)(HomeView)

HomeView este un container convențional Redux (componentă inteligentă). Pentru a utiliza interogările GraphQL în loc de dispecerii de acțiuni pentru a prelua date, vom face unele modificări împreună.

  1. Eliminați mapDispatchToProps () și mapStateToProps () complet.
import React from 'react'import { connect } from 'react-redux'import { bindActionCreators } from 'redux'
export class HomeView extends React.Component {  constructor(props) {    super(props)  }
  render () {    return (      <div className="home">        <h1>Hello World</h1>      </div>    )  }}
export default connect({
})(HomeView)

2. Adăugați mapQueriesToProps () și definiți o interogare GraphQL care va prelua informațiile despre autor. Observați cum este exact aceeași interogare pe care am testat-o ​​la început folosind interfața GraphIQL de pe server.

import React from 'react'import { connect } from 'react-redux'import { bindActionCreators } from 'redux'
export class HomeView extends React.Component {  constructor(props) {    super(props)  }
  render () {    return (      <div className="home">        <h1>Hello World</h1>      </div>    )  }}
// NOTE: This will be automatically fired when the component is rendered, sending this exact GraphQL query to the backend.const mapQueriesToProps = ({ ownProps, state }) => {  return {    data: {      query: gql`        query {          author(firstName:"Edmond", lastName: "Jones"){            firstName            posts {              title            }          }        }      `    }  }}
export default connect({
})(HomeView)

3. Înlocuiți conectarea din react-redux cu conectarea din react-apollo și treceți mapQueriesToProps ca argument. Odată ce mapQueriesToProps este conectat la ApolloClient, interogarea va prelua automat datele din backend atunci când este redat HomeView și va transmite datele prin recuzită.

import React from 'react'import { connect } from 'react-apollo' // NOTE: different connect!import gql from 'graphql-tag' // NOTE: lets us define GraphQL queries in a template language
export class HomeView extends React.Component {  constructor(props) {    super(props)  }
render () {    return (      <div className="home">        <h1>Hello World</h1>      </div>    )  }}
const mapQueriesToProps = ({ ownProps, state }) => {  return {    data: {      query: gql`        query {          author(firstName:"Edmond", lastName: "Jones"){            firstName            posts {              title            }          }        }      `    }  }}
export default connect({  mapQueriesToProps})(HomeView)

4. Redați datele transmise din recuzită:

import React from 'react'import { connect } from 'react-apollo' // NOTE: different connect!import gql from 'graphql-tag' // NOTE: lets us define GraphQL queries in a template language
export class HomeView extends React.Component {  constructor(props) {    super(props)  }
  render () {    const author = this.props.data.author    if (!author) {      return <h1>Loading</h1>    }
    return (      <div>        <h1>{author.firstName}'s posts</h1>        {author.posts && author.posts.map((post, idx) => (          <li key={idx}>{post.title}</li>        ))}      </div>    )  }}
const mapQueriesToProps = ({ ownProps, state }) => {  return {    data: {      query: gql`        query {          author(firstName:"Edmond", lastName: "Jones"){            firstName            posts {              title            }          }        }      `    }  }}
export default connect({  mapQueriesToProps})(HomeView)

Dacă totul a mers bine, HomeView-ul dvs. redat ar trebui să arate ca mai jos:

1612010048 819 Cum sa utilizati GraphQL in aplicatia dvs

Pentru a prelua și reda datele dorite, nu a trebuit să scriem niciun distribuitor de acțiuni, reductor sau normalizator. Tot ce trebuia să facem pentru client a fost să scriem o singură interogare GraphQL!

Ne-am atins cu succes obiectivul inițial. Dar această întrebare a fost destul de simplă. Ce se întâmplă dacă am dori să afișăm toți autorii în loc de un singur autor?

5. Obținerea și mai multor date

Pentru a prelua și afișa toți autorii, trebuie să ne actualizăm interogarea GraphQL și metoda de redare:

import React from 'react'import { connect } from 'react-apollo' // NOTE: different connect!import gql from 'graphql-tag' // NOTE: lets us define GraphQL queries in a template language
export class HomeView extends React.Component {  constructor(props) {    super(props)  }
render () {    const authors = this.props.data.authors    if (!authors) {      return <h1>Loading</h1>    }
    return (      <div>        {authors.map((author, idx) => (          <div key={'author-'+idx}>            <h1>{author.firstName}'s posts</h1>            {author.posts && author.posts.map((post, idx) => (              <li key={idx}>{post.title}</li>            ))}          </div>        ))}      </div>    )  }}
const mapQueriesToProps = ({ ownProps, state }) => {  return {    data: {      query: gql`        query {          authors {            firstName            posts {              title            }          }        }      `    }  }}
export default connect({  mapQueriesToProps})(HomeView)

Cu toate acestea, odată ce actualizați pagina HomeView a browserului, veți observa că aveți o eroare în consolă:

ApolloError {graphQLErrors: Array[1], networkError: nedefinit, mesaj: „Eroare GraphQL: Nu se poate interoga câmpul„ autori ”la tipul„ Interogare ”. V-ați referit la „autor”? ”}

Ah corect! În serverul nostru GraphQL, nu am definit cu adevărat cum să preluăm autori.

Să ne întoarcem la serverul nostru și să vedem ce avem. Deschideți fișierul apollo-starter-kit / data / resolvers.js

import { Author, FortuneCookie } from './connectors';
const resolvers = {  Query: {    author(_, args) {      return Author.find({ where: args });    },    getFortuneCookie() {      return FortuneCookie.getOne()    }  },  Author: {    posts(author) {      return author.getPosts();    },  },  Post: {    author(post) {      return post.getAuthor();    },  },};
export default resolvers;

Privind rezolvatorul de interogări, observăm că serverul nostru GraphQL înțelege doar autor și getFortuneCookie interogări acum. Ar trebui să-l învățăm cum să „rezolvăm” interogarea autori.

import { Author, FortuneCookie } from './connectors';
const resolvers = {  Query: {    author(_, args) {      return Author.find({ where: args });    },    getFortuneCookie() {      return FortuneCookie.getOne()    },    authors() { // the query "authors" means returning all authors!      return Author.findAll({})    }  },  ...};
export default resolvers;

Nu am terminat încă. Deschideți fișierul apollo-starter-kit / data / schema.js

const typeDefinitions = `...
type Query {  author(firstName: String, lastName: String): Author  getFortuneCookie: String}schema {  query: Query}`;
export default [typeDefinitions];

Această schemă arată clar la ce fel de întrebări ar trebui să se aștepte serverul. Nu se așteaptă autori interogare încă așa că hai să o actualizăm.

const typeDefinitions = `...
type Query {  author(firstName: String, lastName: String): Author  getFortuneCookie: String,  authors: [Author] // 'authors' query should return an array of                     // Author}schema {  query: Query}`;
export default [typeDefinitions];

Acum că serverul nostru GraphQL știe ce înseamnă interogarea „autorilor”, să revenim la clientul nostru. Ne-am actualizat deja interogarea, astfel încât să nu trebuie să atingem nimic.

export class HomeView extends React.Component {
...
const mapQueriesToProps = ({ ownProps, state }) => {  return {    data: {      query: gql`        query {          authors {            firstName            posts {              title            }          }        }      `    }  }}
export default connect({  mapQueriesToProps})(HomeView)

Cu această interogare ne așteptăm să obținem toți autorii cu prenumele și postările lor. Continuați și reîmprospătați browserul pentru a vedea dacă obținem datele corecte.

1612010048 104 Cum sa utilizati GraphQL in aplicatia dvs

Dacă totul a mers bine, pagina dvs. HomeView va arăta ca mai sus.

6. Următorii pași

Acest tutorial explorează doar o mică parte din GraphQL și lasă să nu existe o mulțime de concepte, cum ar fi actualizarea datelor de pe server sau utilizarea unui alt server backend (de exemplu, Rails).

În timp ce lucrez pentru a le introduce în tutoriale ulterioare, puteți citi Sashko’s post sau Apollo Client Doc pentru a înțelege mai bine ce se întâmplă sub capotă (de exemplu, ce s-a întâmplat când am înlocuit Provider cu ApolloProvider?).

Căutând în codul sursă al GitHunt, un exemplu de aplicație de tip Apollo Client și Server, pare, de asemenea, o modalitate excelentă de a învăța.

Dacă aveți feedback, vă rugăm să îl lăsați în comentariu. Voi încerca tot posibilul să fiu de ajutor 🙂