Vue 아폴로 v4: 첫눈
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.xprovide/inject
options. The first argument inprovide
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에서 데이터를 실제로 가져올 때 불러오는 상태를 표시하는 것입니다.result
useQuery
을 제외하고 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 클라이언트를 모의하는 것이 더욱 쉽다.나에게 있어서 코드도 더욱 구조화되고 직관적이다.나는 현실 세계의 프로젝트를 시도하기 위해 발표를 기다릴 것이다.
Reference
이 문제에 관하여(Vue 아폴로 v4: 첫눈), 우리는 이곳에서 더 많은 자료를 발견하고 링크를 클릭하여 보았다 https://dev.to/n_tepluhina/vue-apollo-v4-the-first-look-c32텍스트를 자유롭게 공유하거나 복사할 수 있습니다.하지만 이 문서의 URL은 참조 URL로 남겨 두십시오.
우수한 개발자 콘텐츠 발견에 전념 (Collection and Share based on the CC Protocol.)