Vue 아폴로 v4: 첫눈

37944 단어 vuegraphqljavascript

This post requires you to be already familiar with the basics of GraphQL, Apollo Client, and Vue. Shameless plug: I've tried to cover this in . We will also use Vue Composition API. If you're not familiar with this concept, I'd highly recommend reading the Vue Composition API RFC


몇 주 전에 vue apollo(vue.js의 apollo 클라이언트 통합) 4판 알파가 발표되었는데, 나는 즉시 시험해 보기로 결정했다.이 버전은 뭐가 흥분됩니까?기존 API 외에도 Vue Composition API 기반 composables 옵션이 있습니다.나는 과거에 vue apollo에 대해 풍부한 경험을 가지고 있으며, 새로운 API가 이전의 API와 비교해 어떠한지 검사하기로 결정했다.

우리가 사용할 예


새로운 API를 탐색하기 위해서, 나는 나의 Vue + Apollo 강연에서 이미 보여준 예시인 'Vue 영웅' 을 사용할 것이다.이것은 GraphQL API에서 모든 영웅을 검색하는 데 사용되는 간단한 프로그램입니다. 하나는 영웅을 추가하는 데 사용되고, 다른 하나는 영웅을 삭제하는 데 사용됩니다.인터페이스는 다음과 같습니다.

이전 옵션인 API here을 사용하여 소스 코드를 찾을 수 있습니다.GraphQL 서버 포함;프로그램이 정상적으로 작동하려면 그것을 실행해야 합니다.
yarn apollo
이제 새 버전으로 재구성해 봅시다.

장치


첫 번째 단계에서는 프로젝트에서 vue apollo의 이전 버전을 안전하게 삭제할 수 있습니다.
yarn remove vue-apollo
우리는 새 것을 설치해야 한다.버전 4부터 필요한 패키지만 설치하고 사용할 API를 선택할 수 있습니다.우리의 예에서 우리는 새로운composables 문법을 시도하고 싶다.
yarn add @vue/apollo-composable
Composition API는 Vue 3의 일부이며 아직 릴리즈되지 않았습니다.다행히도 Vue 2와 함께 작업할 수 있는 별도의 라이브러리를 사용할 수 있으므로 이제 설치해야 합니다.
yarn add @vue/composition-api
현재, 우리는 src/main.js 파일을 열고 거기에서 약간의 변경을 진행합시다.먼저 Vue 애플리케이션에 Composition API 플러그인을 포함해야 합니다.
// main.js

import VueCompositionApi from "@vue/composition-api";

Vue.use(VueCompositionApi);
Apollo 클라이언트를 설정하려면 새로운 apollo-composable 라이브러리를 사용해야 합니다.GraphQL 엔드포인트에 대한 링크를 정의하고 나중에 클라이언트 구조 함수에 전달할 캐시를 만듭니다.
// main.js

import { createHttpLink } from "apollo-link-http";
import { InMemoryCache } from "apollo-cache-inmemory";

const httpLink = createHttpLink({
  uri: "http://localhost:4000/graphql"
});

const cache = new InMemoryCache();
이제 Apollo 클라이언트 인스턴스를 만들 수 있습니다.
// main.js

import { createHttpLink } from "apollo-link-http";
import { InMemoryCache } from "apollo-cache-inmemory";
import { ApolloClient } from "apollo-client";

const httpLink = createHttpLink({
  uri: "http://localhost:4000/graphql"
});

const cache = new InMemoryCache();

const apolloClient = new ApolloClient({
  link: httpLink,
  cache
});
클라이언트를 만드는 것은 Vue Apollo의 이전 버전과 다를 것이 없습니다. 현재까지는 Vue와 아무런 관계가 없습니다. 우리는 단지 Apollo 클라이언트 자체를 만드는 것입니다.다른 것은, 우리는 더 이상 apolloProvider을 창설할 필요가 없다!Apollo Provider 인스턴스 없이도 클라이언트에서 Vue에 이르는 애플리케이션을 제공하기만 하면 됩니다.
// main.js
import { provide } from "@vue/composition-api";
import { DefaultApolloClient } from "@vue/apollo-composable";

new Vue({
  setup() {
    provide(DefaultApolloClient, apolloClient);
  },
  render: h => h(App)
}).$mount("#app");

provide here is imported from the @vue/composition-api package, and it enables dependency injection similar to the 2.x provide/inject options. The first argument in provide is a key, second is a value


3.x
4.x 조합 가능한 문법


질의 추가


페이지에 Vue Hero 목록을 표시하려면 allHeroes 쿼리를 작성해야 합니다.
// graphql/allHeroes.query.gql

query AllHeroes {
  allHeroes {
    id
    name
    twitter
    github
    image
  }
}
App.vue 구성 요소에서 사용하기 때문에 다음과 같이 가져옵니다.
// App.vue

import allHeroesQuery from "./graphql/allHeroes.query.gql";
이 질의는 옵션 API를 통해 Vue 구성 요소 apollo 속성에 사용됩니다.
// App.vue

  name: "app",
  data() {...},
  apollo: {
    allHeroes: {
      query: allHeroesQuery,s
    }
  }
이제 Composition API와 함께 작동하도록 App.vue을 수정합니다.실제로 기존 구성 요소에 옵션 추가 - a setup:
// App.vue

export default {
  name: "app",
  setup() {},
  data() {...}
여기에서, setup 함수에서, 우리는 vue apollo composables를 사용할 것입니다. 템플릿에서 사용할 결과를 되돌려야 합니다.첫 번째 단계는 allHeroes 쿼리의 결과를 얻는 것입니다. 따라서 첫 번째 조합 가능한 항목을 가져와 GraphQL 쿼리를 전달해야 합니다.
// App.vue

import allHeroesQuery from "./graphql/allHeroes.query.gql";
import { useQuery } from "@vue/apollo-composable";
export default {
  name: "app",
  setup() {
    const { result } = useQuery(allHeroesQuery);

    return { result }
  },
  data() {...}

useQuery can accept up to three parameters: first is GraphQL document containing the query, second is variables object, and the third is query options. In this case, we use default options, and we don't need to pass any variables to the query, so we're passing only the first one


여기 result이 뭐예요?이것은 이름과 완전히 일치합니다. 이것은 GraphQL 조회의 결과입니다. allHeroes 그룹을 포함하지만, 반응 대상이기도 합니다. 따라서 이것은 Vue ref 입니다.이것이 바로 생성된 그룹을 value 속성에 포장하는 이유입니다.

Vue가 템플릿에서 자동으로 확장되면 목록을 result.allHeroes씩 교체하면 됩니다.
<template v-for="hero in result.allHeroes">
그러나, 이 그룹의 초기 값은 undefined이 될 것이다. 왜냐하면 결과는 여전히 API에서 불러오기 때문이다.우리는 result && result.allHeroes과 비슷한 결과를 얻었는지 확인하기 위해 여기에 검사를 추가할 수 있지만, v4는 우리가 이 일을 완성하는 데 유용한 조수가 있다. 바로 useResult이다.이것은 매우 유용한 도구로서 API에서 얻은 결과를 만드는 데 도움을 줄 수 있습니다. 특히 한 검색에서 깊이 있는 중첩된 데이터나 몇 개의 다른 결과를 얻으려면 다음과 같습니다.
<template v-for="hero in allHeroes">

<script>
import { useQuery, useResult } from "@vue/apollo-composable";
export default {
  setup() {
    const { result } = useQuery(allHeroesQuery);
    const allHeroes = useResult(result, null, data => data.allHeroes)

    return { allHeroes }
  },
}
</script>
useResult은 세 가지 인자를 받아들인다:GraphQL 조회 결과, 기본값 (이 예는 null) 과 픽업 함수. 이 함수는 우리가 결과 대상에서 검색하고자 하는 데이터를 되돌려줍니다.이 예에서 allHeroes과 같은 속성만 포함된 경우 다음과 같이 간략화할 수 있습니다.
// App.vue

setup() {
  const { result } = useQuery(allHeroesQuery);
  const allHeroes = useResult(result)

  return { allHeroes }
},
남은 유일한 일은 API에서 데이터를 실제로 가져올 때 불러오는 상태를 표시하는 것입니다.resultuseQuery을 제외하고 loading을 반환할 수 있습니다.
// App.vue
setup() {
  const { result, loading } = useQuery(allHeroesQuery);
  const allHeroes = useResult(result)

  return { allHeroes, loading }
},
템플릿에 조건부로 표시할 수 있습니다.
<h2 v-if="loading">Loading...</h2>
v3 코드를 새 코드와 비교해 보겠습니다.
3.x
4.x 조합 가능한 문법


새로운 문법은 더욱 상세하지만 맞춤형으로 만들 수 있다. (응답을 형성하기 위해서는 v3 문법에 update 속성을 추가해야 한다.)나는 우리가 모든 조회를 위해 loading을 정확하게 공개할 수 있기를 바란다. 이를 전체 $apollo 대상의 삽입 속성으로 사용하는 것이 아니라.

돌연변이를 연구하다


이제 우리도 새로운 문법을 재구성합시다.이 응용 프로그램에는 두 가지 변형이 있습니다. 하나는 새 영웅을 추가하는 데 사용되고, 다른 하나는 기존 영웅을 삭제하는 데 사용됩니다.
// graphql/addHero.mutation.gql

mutation AddHero($hero: HeroInput!) {
  addHero(hero: $hero) {
    id
    twitter
    name
    github
    image
  }
}
// graphql/deleteHero.mutation.gql

mutation DeleteHero($name: String!) {
  deleteHero(name: $name)
}
Options API 구문에서 Vue 인스턴스 $apollo 속성의 한 가지 방법으로 변이를 호출했습니다.
this.$apollo.mutate({
  mutation: mutationName,
})
addHero부터 재구성해 봅시다.질의와 유사하게 돌연변이를 App.vue으로 가져오고 이를 매개변수로 useMutation의 조합 가능한 함수에 전달해야 합니다.
// App.vue

import addHeroMutation from "./graphql/addHero.mutation.gql";
import { useQuery, useResult, useMutation } from "@vue/apollo-composable";

export default {
  setup() {
    const { result, loading } = useQuery(allHeroesQuery);
    const allHeroes = useResult(result)

    const { mutate } = useMutation(addHeroMutation)
  },
}
이곳의 mutate은 사실상 하나의 방법이다. 우리는 그것을 호출해서GraphQL API 단점에 돌변을 보내야 한다.그러나 addHero이 돌변한 상황에서 우리는 목록에 추가하고자 하는 영웅을 정의하기 위해 변수 hero을 보내야 한다.좋습니다. setup 함수에서 이 방법을 되돌려주고 Options API 방법에서 사용할 수 있습니다.mutate 함수를 다시 명명합시다. 우리는 두 개의 돌연변이가 있을 것이기 때문에 그것에 대해 더욱 직관적인 이름을 붙이는 것은 좋은 생각입니다.
// App.vue

setup() {
  const { result, loading } = useQuery(allHeroesQuery);
  const allHeroes = useResult(result)

  const { mutate: addNewHero } = useMutation(addHeroMutation)

  return { allHeroes, loading, addNewHero }
},
현재 우리는 구성 요소의 기존 addHero 방법에서 그것을 호출할 수 있다.
export default {
  setup() {...},
  methods: {
    addHero() {
      const hero = {
        name: this.name,
        image: this.image,
        twitter: this.twitter,
        github: this.github,
        github: this.github
      };

      this.addNewHero({ hero });
    }
  }
}
보시다시피 우리는 변이를 호출하는 순간에 변수를 전달했다.또 다른 방법은 옵션스 대상에 변수를 추가하여 두 번째 매개 변수로 useMutation 함수에 전달할 수 있다.
const { mutate: addNewHero } = useMutation(addHeroMutation, {
  variables: {
    hero: someHero
  }
})
이제 GraphQL 서버에 변종이 성공적으로 전송됩니다.단, 응답이 성공한 후에 로컬 아폴로 캐시를 업데이트해야 합니다. 그렇지 않으면, 영웅 목록은 페이지를 다시 불러오기 전에 변경되지 않습니다.따라서 Apollo 캐시에서 allHeroes 조회를 읽고 새로운 영웅의 목록을 추가하여 다시 작성해야 합니다.이 작업은 update 함수에서 수행됩니다(options 매개변수를 사용하여 variables과 같이 전달할 수 있습니다).
// App.vue

setup() {
  const { result, loading } = useQuery(allHeroesQuery);
  const allHeroes = useResult(result)

  const { mutate: addNewHero } = useMutation(addHeroMutation, {
    update: (cache, { data: { addHero } }) => {
      const data = cache.readQuery({ query: allHeroesQuery });
      data.allHeroes = [...data.allHeroes, addHero];
      cache.writeQuery({ query: allHeroesQuery, data });
    }
  })

  return { allHeroes, loading, addNewHero }
},
지금, 우리가 새로운 영웅을 추가할 때, 로드 상태는 무엇입니까?v3은 외부 플래그를 생성하고 finally에서 변경하여 다음을 수행합니다.
// App.vue

export default {
  data() {
    return {
      isSaving: false
    };
  },
  methods: {
    addHero() {
      ...
      this.isSaving = true;
      this.$apollo
        .mutate({
          mutation: addHeroMutation,
          variables: {
            hero
          },
          update: (store, { data: { addHero } }) => {
            const data = store.readQuery({ query: allHeroesQuery });
            data.allHeroes.push(addHero);
            store.writeQuery({ query: allHeroesQuery, data });
          }
        })
        .finally(() => {
          this.isSaving = false;
        });
    }
  }
}
v4 composition API에서는 useMutation 함수에서 지정된 돌연변이의 로드 상태를 간단히 반환할 수 있습니다.
setup() {
  ...
  const { mutate: addNewHero, loading: isSaving } = useMutation(
    addHeroMutation,
    {
      update: (cache, { data: { addHero } }) => {
        const data = cache.readQuery({ query: allHeroesQuery });
        data.allHeroes = [...data.allHeroes, addHero];
        cache.writeQuery({ query: allHeroesQuery, data });
      }
    }
  );

  return {
    ...
    addNewHero,
    isSaving
  };
}
v3 및 v4 콤보 API 코드를 비교해 보겠습니다.
3.x
4.x 조합 가능한 문법


내가 보기에,composition API 코드는 더욱 구조화되었고, 외부 로고도 불러오는 상태를 유지할 필요가 없다.deleteHero 변이는 매우 유사한 방식으로 재구성할 수 있다. 중요한 점을 제외하고 update 함수에서 우리는 이름에 따라 찾은 영웅을 삭제해야 한다. 이 명칭은 템플릿에서만 사용할 수 있다(우리는 v-for 명령을 사용하여 영웅열표에서 교체를 하고 hero.name 순환에서 v-for을 얻지 못하기 때문이다).이것이 바로 우리가 돌연변이를 호출하는 곳에서 옵션 매개 변수 중의 update 함수를 직접 전달해야 하는 이유이다.
<vue-hero
  v-for="hero in allHeroes"
  :hero="hero"
  @deleteHero="
    deleteHero(
      { name: $event },
      {
        update: cache => updateHeroAfterDelete(cache, $event)
      }
    )
  "
  :key="hero.name"
></vue-hero>

<script>
  export default {
    setup() {
      ...

      const { mutate: deleteHero } = useMutation(deleteHeroMutation);
      const updateHeroAfterDelete = (cache, name) => {
        const data = cache.readQuery({ query: allHeroesQuery });
        data.allHeroes = data.allHeroes.filter(hero => hero.name !== name);
        cache.writeQuery({ query: allHeroesQuery, data });
      };
      return {
        ...
        deleteHero,
        updateHeroAfterDelete,
      };
    }
  }
</script>

결론


나는 vue apollo v4 composables가 제공하는 코드의 추상적인 단계를 정말 좋아한다.provider을 만들지 않고 $apollo 대상을 Vue 실례에 주입하지 않으면 단원 테스트에서 아날로그 Apollo 클라이언트를 모의하는 것이 더욱 쉽다.나에게 있어서 코드도 더욱 구조화되고 직관적이다.나는 현실 세계의 프로젝트를 시도하기 위해 발표를 기다릴 것이다.

좋은 웹페이지 즐겨찾기