點燈坊

失くすものさえない今が強くなるチャンスよ

使用 Vue Apollo 建立 Fragment

Sam Xiao's Avatar 2019-12-22

Vue Apollo 也支援 GraphQL 的 Fragment,讓我們將 Field 重複部分抽成 Fragment 方便維護。

Version

macOS Catalina 10.15.2
WebStorm 2019.3
Node 12.4.0
Vue CLI 4.1.1
Vue 2.6.10
Vue Apollo 3.0.0-beta.11

Vue Apollo

src/App.vue

<template>
  <div>
    <ul>
      <li v-for="(item, index) in books" :key="index">
        {{ item.title }}:{{ item.price }} / {{ item.quantity }}
      </li>
    </ul>
  </div>
</template>

<script>
import gql from 'graphql-tag'

let query = gql(`
  query {
    books {
      title
      price
      quantity
    }
  }
`)

export default {
  name: 'app',
  apollo: {
    books: {
      query
    }
  }
}
</script>

14 行

let query = gql(`
  query {
    books {
      title
      price
      quantity
    }
  }
`)

使用 books query,且回傳 titlepricequantity 3 個 field。

Fragment

src/App.vue

<template>
  <div>
    <ul>
      <li v-for="(item, index) in books" :key="index">
        {{ item.title }}:{{ item.price }} / {{ item.quantity }}
      </li>
    </ul>
  </div>
</template>

<script>
import gql from 'graphql-tag'

let query = gql(`
  query {
    books {
      ...bookFields
    }
  }

  fragment bookFields on Book {
    title
    price
    quantity
  }
`)

export default {
  name: 'app',
  apollo: {
    books: {
      query
    }
  }
}
</script>

14 行

let query = gql(`
  query {
    books {
      ...bookFields
    }
  }

  fragment bookFields on Book {
    title
    price
    quantity
  }
`)

titlepricequantity 3 個 field 在其他 query 也使用,可使用 fragment 將這些 field 宣告成 fragment,on 後面接 type。

之後在 query 可使用類似 ES6 的 ... spread operator 將其展開,如此多個 query 都可共用該 fragment。

src/App.vue

<template>
  <div>
    <ul>
      <li v-for="(item, index) in books" :key="index">
        {{ item.title }}:{{ item.price }} / {{ item.quantity }}
      </li>
    </ul>
  </div>
</template>

<script>
import gql from 'graphql-tag'

let books = function() {
  let query = gql`
    query {
      books {
        ...bookFields
      }
    }
    ${ this.$options.fragments.bookFields }
  `
  return { query }
}

let bookFields = gql`
  fragment bookFields on Book {
    title
    price
    quantity
  }
`

export default {
  name: 'app',
  apollo: {
    books
  },
  fragments: {
    bookFields
  }
}
</script>

之前 fragment 寫法雖然能達到 query 間共用,但仍不夠靈活,需侷限在同一個 smart query 內。

34 行

export default {
  name: 'app',
  apollo: {
    books
  },
  fragments: {
    bookFields
  }
}

比較理想的方式是在 fragments property 下令外宣告 bookFields fragment。

26 行

let bookFields = gql`
  fragment bookFields on Book {
    title
    price
    quantity
  }
`

定義 bookFields fragment。

14 行

let books = function() {
  let query = gql`
    query {
      books {
        ...bookFields
      }
    }
    ${ this.$options.fragments.bookFields }
  `
  return { query }
}

books query 中使用 this.$options.fragments 取得 bookFields fragment,由於使用了 this,因此必須使用 function expression,不能使用 arrow function。

fragment000

Conclusion

  • Vue Apollo 目前若使用 fragment,無法使用 Webpack Loader 寫法將 query 與 fragment 獨立出 *.graphql,只能使用 gql() 動態將 string 轉成 GraphQL AST

Reference

Vue Apollo, Using fragments