GraphQL: n käyttäminen Redux-sovelluksessa

Tietojen noutaminen ja hallinta Reduxissa vaatii liikaa työtä. Kuten Sashko Stubailo huomauttaa:

Valitettavasti palvelintietojen asynkronisen lataamisen mallit Redux-sovelluksessa eivät ole yhtä vakiintuneita, ja niihin liittyy usein ulkoisten auttajakirjastojen, kuten redux-saagan, käyttö. Sinun on kirjoitettava mukautettu koodi, jotta voit soittaa palvelimesi päätepisteisiin, tulkita tietoja, normalisoida ne ja lisätä ne kauppaan - kaikki samalla kun pidät kirjaa erilaisista virheistä ja lataustiloista.

Tämän opetusohjelman loppuun mennessä olet oppinut ratkaisemaan tämän ongelman antamalla Apollo-asiakkaan hakea ja hallita tietoja puolestasi. Sinun ei enää tarvitse kirjoittaa useita toimintojen välittäjiä, pelkistimiä ja normalisoijia hakemaan ja synkronoimaan tietoja käyttöliittymän ja käyttöliittymän välillä.

Mutta ennen opetusohjelman aloittamista varmista, että:

  • Tiedät GraphQL-kyselyjen perusteet - jos olet täysin uusi GraphQL-käyttäjä, sinun tulisi palata tämän opetusohjelman tekemisen jälkeen.
  • Sinulla on jonkin verran kokemusta työskentelystä React / Redux -palvelun kanssa - jos ei, sinun pitäisi palata takaisin tekemällä reaktio- ja redux-opetusohjelma.

Tässä opetusohjelmassa käymme läpi 6 osiota yhdessä.

  1. Palvelinympäristön määrittäminen (nopea)
  2. Redux boilerplate -sovelluksen määrittäminen
  3. GraphQL-asiakkaan (Apollo-asiakas) lisääminen
  4. Tietojen noutaminen GraphQL-kyselyllä
  5. Haetaan vieläkin enemmän tietoja
  6. Seuraavat vaiheet

1. Palvelinympäristön määrittäminen

Ensinnäkin tarvitsemme GraphQL-palvelimen. Helpoin tapa saada käynnissä oleva palvelin on suorittaa tämä mahtava opetusohjelma.

Jos tunnet olosi laiskaksi, voit vain kloonata reponi, joka on melkein sama palvelin, jonka saisit, jos teit opetusohjelman itse. Palvelin tukee GraphQL-kyselyjä tietojen hakemiseksi SQLite-tietokannasta.

Suoritetaan se ja katsotaan, toimiiko se oikein:

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

Palvelimen on oltava käynnissä osoitteessa // localhost: 8080 / graphql. Siirry tälle sivulle ja katso, saatko toimivan GraphiQL-käyttöliittymän, jolla on tällaisia ​​tuloksia:

GraphiQL: n avulla voit testata erilaisia ​​kyselyjä ja nähdä heti vastauksen palvelimelta. Jos emme halua kirjoittajan sukunimeä ja fortune-evästeviestiä vastaukseksi, voimme päivittää kyselyn seuraavasti:

Ja juuri siitä pidämme. Vahvistimme, että palvelimemme toimii hyvin ja palauttaa hyvät vastaukset, joten aloitetaan asiakkaan rakentaminen.

2. Redux-kattilasovelluksen määrittäminen

Yksinkertaisuuden vuoksi käytämme redux-kattilaa, jotta voimme saada kaikki asetukset (esim. Babel, webpack, CSS jne.) Ilmaiseksi. Pidän tästä kattilasta, koska sen asetuksia on helppo seurata ja se on vain asiakaspuoli - mikä tekee siitä täydellisen tälle opetusohjelmalle.

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

Siirrytään kohtaan // localhost: 3000 / nähdäksesi onko asiakaspalvelin käynnissä.

Jee! Asiakas on käynnissä. Meidän on aika alkaa lisätä GraphQL-asiakasohjelma. Jälleen tavoitteemme on saada tiedot helposti palvelimelta ja tehdä ne laskeutumissivulla (HomeView) ilman paljon vaivaa käyttämällä GraphQL-kyselyitä.

3. GraphQL-asiakkaan (Apollo Client) lisääminen

Asenna paketit apollo-client, react-apollo ja graphql-tag.

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

Avaa sitten tiedosto src / containers / AppContainer.js, joka on Redux-sovelluksemme juuri. Tässä siirrämme redux-myymälän lapsikomponenteille käyttämällä Provider from -redux -palvelua.

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 ( ) }}
export default AppContainer

Meidän on alustettava ApolloClient ja vaihdettava Provider from react-redux ApolloProvider from react-apollosta.

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('//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 ( ) }}
export default AppContainer

Se siitä! Lisäsimme juuri helposti GraphQL-asiakkaan tavalliseen Redux-sovellukseen.

Mennään eteenpäin ja kokeillaan ensimmäistä GraphQL-kyselyä.

4. Tietojen noutaminen GraphQL-kyselyillä

Avaa 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 ( 

Hello World

) }}
// 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 on tavanomainen Redux-säilö (älykäs komponentti). Jos haluat käyttää GraphQL-kyselyjä toimintojen välittäjien sijasta tietojen noutamiseen, teemme joitain muutoksia yhdessä.

  1. Poista mapDispatchToProps () ja mapStateToProps () kokonaan.
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 ( 

Hello World

) }}
export default connect({
})(HomeView)

2. Lisää mapQueriesToProps () ja määritä GraphQL-kysely, joka noutaa kirjoittajatiedot. Huomaa, kuinka tämä on täsmälleen sama kysely, jonka testasimme alussa palvelimen GraphIQL-käyttöliittymän avulla.

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 ( 

Hello World

) }}
// 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. Korvaa connect from react-redux -sovelluksella connect from react-apollo ja anna argumentti mapQueriesToProps. Kun mapQueriesToProps on yhdistetty ApolloClientiin, kysely hakee tiedot automaattisesti taustasta, kun HomeView renderöidään, ja välittää tiedot rekvisiittaan.

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 ( 

Hello World

) }}
const mapQueriesToProps = ({ ownProps, state }) => { return { data: { query: gql` query { author(firstName:"Edmond", lastName: "Jones"){ firstName posts { title } } } ` } }}
export default connect({ mapQueriesToProps})(HomeView)

4. Tee rekvisiitasta välitetyt tiedot:

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 

Loading

}
 return ( 

{author.firstName}'s posts

{author.posts && author.posts.map((post, idx) => (
  • {post.title}
  • ))} ) }}
    const mapQueriesToProps = ({ ownProps, state }) => { return { data: { query: gql` query { author(firstName:"Edmond", lastName: "Jones"){ firstName posts { title } } } ` } }}
    export default connect({ mapQueriesToProps})(HomeView)

    If all went well, your rendered HomeView should look like below:

    To fetch and render the data we wanted, we didn’t have to write any action dispatcher, reducer, or normalizer. All we had to do on the client was to write a single GraphQL query!

    We successfully achieved our initial goal. But that query was quite simple. What if we wanted to display all authors instead of just one author?

    5. Fetching even more data

    In order to fetch and display all authors, we have to update our GraphQL query and render method:

    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 

    Loading

    }
     return ( {authors.map((author, idx) => ( 

    {author.firstName}'s posts

    {author.posts && author.posts.map((post, idx) => (
  • {post.title}
  • ))} ))} ) }}
    const mapQueriesToProps = ({ ownProps, state }) => { return { data: { query: gql` query { authors { firstName posts { title } } } ` } }}
    export default connect({ mapQueriesToProps})(HomeView)

    However, once you refresh your browser HomeView page, you will notice that you have an error in your console:

    ApolloError {graphQLErrors: Array[1], networkError: undefined, message: “GraphQL error: Cannot query field “authors” on type “Query”. Did you mean “author”?”}

    Ah, right! In our GraphQL server, we didn’t really define how to fetch authors.

    Let’s go back to our server and see what we have. Open the file 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;

    Looking at Query resolver, we notice that our GraphQL server only understands author and getFortuneCookie queries now. We should teach it how to “resolve” the query authors.

    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;

    We are not done yet. Open the file apollo-starter-kit/data/schema.js

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

    This Schema makes it clear what kind of queries the server should expect. It doesn’t expect authors query yet so let’s update it.

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

    Now that our GraphQL server knows what the “authors” query means, let’s go back to our client. We already updated our query so we don’t have to touch anything.

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

    Tämän kyselyn avulla odotamme kaikkien kirjoittajien etunimet ja viestit. Päivitä selain ja tarkista, saammeko oikeat tiedot.

    Jos kaikki meni hyvin, HomeView-sivusi näyttää yllä olevalta.

    6. Seuraavat vaiheet

    Tämä opetusohjelma tutkii vain pientä osaa GraphQL: stä ja jättää pois paljon käsitteitä, kuten tietojen päivittäminen palvelimella tai toisen taustapalvelimen (esim. Rails) käyttäminen.

    Vaikka pyrin esittelemään näitä seuraavissa opetusohjelmissa, voit lukea Sashkon viestin tai Apollo Client Docin ymmärtääksesi paremmin, mitä hupun alla tapahtuu (esimerkiksi mitä tapahtui, kun vaihdoimme Providerin ApolloProvideriin?).

    Kaivaminen GitHuntin, täyden pinon Apollo Client- ja Server-esimerkkisovelluksen lähdekoodiin näyttää myös hyvältä tavalta oppia.

    Jos sinulla on palautetta, jätä se kommenttiin. Yritän parhaani mukaan olla hyödyllinen :)