介紹
前面兩篇ApolloData相關基本設定介紹後,接下來是 graphql 的HOC綁定 gql時候的語法,以及如何使用 Query 與 Mutation
以最下方的github範例 components/PostList.js 這隻的 Query來介紹,先觀察一下 PostList 裡面的 data 有 loading, error, allPosts, _allPostsMeta 這些 props 屬性,另外還有一個 loadMorePosts 的 method ,而這些資料其實是 graphql HOC 綁定 gql 後產生出來的
function PostList ({
data: { loading, error, allPosts, _allPostsMeta },
loadMorePosts
})
可以看到graphql 第一個 allPosts 是 gql的 查詢 json payload, 而 options中 第一個 data 就是返回的資料,如果沒有特別命就會返回資料在 props.data, 第二個 props 中寫上一個loadMorePosts method 被綁定的元件 即有這個 props method ,至於 元件綁定後 loading 與 error 是原本 ApolloData 提供的 , allPosts ,_allPostsMeta則是返回資料
export default graphql(allPosts, {
options: {
variables: allPostsQueryVars
},
props: ({ data }) => ({
data,
loadMorePosts: () => {
以下省略
而loading 當 ApolloData 再發 request 的時候這邊會自動變成 true 所以加載資料可以透過 loading 來切換畫面, 以下是全部 Code 的樣貌 github在下面
import { graphql } from 'react-apollo'
import gql from 'graphql-tag'
import ErrorMessage from './ErrorMessage'
import PostUpvoter from './PostUpvoter'
const POSTS_PER_PAGE = 10
function PostList ({
data: { loading, error, allPosts, _allPostsMeta },
loadMorePosts
}) {
if (error) return <ErrorMessage message='Error loading posts.' />
if (allPosts && allPosts.length) {
const areMorePosts = allPosts.length < _allPostsMeta.count
return (
<section>
<ul>
{allPosts.map((post, index) => (
<li key={post.id}>
<div>
<span>{index + 1}. </span>
<a href={post.url}>{post.title}</a>
<PostUpvoter id={post.id} votes={post.votes} />
</div>
</li>
))}
</ul>
{areMorePosts ? (
<button onClick={() => loadMorePosts()}>
{' '}
{loading ? 'Loading...' : 'Show More'}{' '}
</button>
) : (
''
)}
</section>
)
}
return <div>Loading</div>
}
export const allPosts = gql`
query allPosts($first: Int!, $skip: Int!) {
allPosts(orderBy: createdAt_DESC, first: $first, skip: $skip) {
id
title
votes
url
createdAt
}
_allPostsMeta {
count
}
}
`
export const allPostsQueryVars = {
skip: 0,
first: POSTS_PER_PAGE
}
// The `graphql` wrapper executes a GraphQL query and makes the results
// available on the `data` prop of the wrapped component (PostList)
export default graphql(allPosts, {
options: {
variables: allPostsQueryVars
},
props: ({ data }) => ({
data,
loadMorePosts: () => {
return data.fetchMore({
variables: {
skip: data.allPosts.length
},
updateQuery: (previousResult, { fetchMoreResult }) => {
if (!fetchMoreResult) {
return previousResult
}
return Object.assign({}, previousResult, {
// Append the new posts results to the old one
allPosts: [...previousResult.allPosts, ...fetchMoreResult.allPosts]
})
}
})
}
})
})(PostList)
loadMorePosts 的 method 主要是使用 apolloData 提供的 data.fetchMore 這個 method 這邊的 data 就是grpahql 綁定的 gql 語法 ,這邊只是給他不同的 variables skip 抓目前已經有載入多少比數,在使用 updataQuery 把新抓回來的資料在透過新舊疊加,產生出一的一筆 allPosts: [...previousResult.allPosts, ...fetchMoreResult.allPosts] 如果失敗就
返回之前的結果
if (!fetchMoreResult) {
return previousResult
}
loadMorePosts: () => {
return data.fetchMore({
variables: {
skip: data.allPosts.length
},
updateQuery: (previousResult, { fetchMoreResult }) => {
if (!fetchMoreResult) {
return previousResult
}
return Object.assign({}, previousResult, {
// Append the new posts results to the old one
allPosts: [...previousResult.allPosts, ...fetchMoreResult.allPosts]
})
}
})
}
接下來看 components/PostUpvoter.js 這隻的 Mutation 的部分
這邊可以看 props 中有兩個 ownProps 與 mutate (ApolloData提供) , ownProps是搭配 optimisticResponse
(樂觀UI,點擊後先反應給使用,之後再執行request) 中看到 updatePost 使用 id: ownProps.id 這個的 ownProps 就是綁定的物件的有重新 render 的效果,mutate 要使用它 ApolloData提供的 mutate 包起來 預設是query不需要
export default graphql(upvotePost, {
props: ({ ownProps, mutate }) => ({
upvote: (id, votes) =>
mutate({
variables: { id, votes },
optimisticResponse: {
__typename: 'Mutation',
updatePost: {
__typename: 'Post',
id: ownProps.id,
votes: ownProps.votes + 1
}
}
})
})
})(PostUpvoter)
總結
ApolloData 最常見的Client 使用方式就是 這兩個Query與Mutaion ,而常常搞混的是哪些是 props的對應 也應該要去理解 ApolloData 還有提供哪些 props 可以使用,這個範例中學到的有loading , error, mutate,ownProps
本範例Github連結檔
https://github.com/zeit/next.js/tree/canary/examples/with-apollo