ApolloClient 在执行突变时所有值都为 null
ApolloClient all values result to null when performing a mutation
我开始使用 ApolloClient,我必须说,文档太糟糕了。
我的应用程序将使用 GraphQL,但需要使用简单的 POST
请求来完成登录,请求 /login
提供用户名和密码,作为表单数据。
伙计,让它工作完全是一场噩梦。
因为我必须使用 apollo-link-rest
我必须首先构建我的客户端:
import ApolloClient from 'apollo-client'
import { InMemoryCache } from 'apollo-cache-inmemory'
import { ApolloLink } from 'apollo-link'
import { createHttpLink } from 'apollo-link-http'
import { onError } from 'apollo-link-error'
import { RestLink } from 'apollo-link-rest'
const cache = new InMemoryCache()
const httpLink = new createHttpLink({
credentials: 'include',
})
const restLink = new RestLink({
endpoints: {
localhost: {
uri: "http://localhost:8080"
}
},
credentials: 'include'
})
const errorLink = onError(({ graphQLErrors, networkError, operation }) => {
if (graphQLErrors) {
graphQLErrors.forEach(({ message, locations, path }) => {
console.log(`[GraphQL error] Message: ${message}, ${path}`)
})
}
if (networkError) {
console.log(
`[Network error ${networkError}] Operation: ${operation.operationName}`
)
}
})
export const client = new ApolloClient({
link: ApolloLink.from([errorLink, restLink, httpLink]),
cache,
})
然后我有我的查询:
const LOGIN_QUERY = gql`
mutation doLogin($username: String!, $password: String!, $formSerializer: any) {
user(input: { username: $username, password: $password})
@rest(
path: "/login"
type: "user"
method: "POST"
endpoint: "localhost"
bodySerializer: $formSerializer
) {
id
name
}
}`
const formSerializer = (data, headers) => {
const formData = new URLSearchParams()
for (let key in data) {
if (data.hasOwnProperty(key)) {
formData.append(key, data[key])
}
}
headers.set('Content-Type', 'application/x-www-form-urlencoded')
return { body: formData, headers }
}
我发现文档没有关于如何发送表单数据的示例,这让我非常疯狂,我不得不 google 做了很多,直到我找到了如何做。
然后我在登录组件中执行查询:
const [doLogin, { data }] = useMutation(LOGIN_QUERY, {
onCompleted: () => {
console.log("Success")
},
onError: () => {
console.log("Poop")
}
})
const handleSubmit = (event) => {
event.preventDefault()
console.log('logging in...')
doLogin({
variables: { username, password, formSerializer },
})
}
服务器让我登录,returns 一个会话 cookie,以及一个包含以下内容的正文:
{
"data": {
"user": {
"id": 1
"name": "Foobar"
}
}
}
当我使用 ApolloClient google chrome 插件检查缓存状态时,缓存有:
user:null
id: null
name: null
所以这是我的问题:
- 我需要设置默认状态吗?
- 文档仅显示首次查询对象的突变,如果对象已存在于缓存中,我能否仅使用突变更新缓存?
- 我需要为每种类型编写解析器吗?
- 还有,为什么我得到空值?
- 是否所有数据都需要包装在一个
data
对象中返回,即使对于 rest 查询也是如此?
- 必须将
formSerializer
作为变量传递给查询,因为我发现它非常丑陋。
如前所述...ApolloClient 文档是我读过的最糟糕的文档之一。一点都不友好。
根据 Response transforming,apollo 期望来自 REST API 的响应如下:
{
"id": 1,
"name": "Apollo"
}
如果你无法控制后端,你可以使用自定义的响应转换器:
responseTransformer: async response => response.json().then(({data}) => data.data?.user)
我开始使用 ApolloClient,我必须说,文档太糟糕了。
我的应用程序将使用 GraphQL,但需要使用简单的 POST
请求来完成登录,请求 /login
提供用户名和密码,作为表单数据。
伙计,让它工作完全是一场噩梦。
因为我必须使用 apollo-link-rest
我必须首先构建我的客户端:
import ApolloClient from 'apollo-client'
import { InMemoryCache } from 'apollo-cache-inmemory'
import { ApolloLink } from 'apollo-link'
import { createHttpLink } from 'apollo-link-http'
import { onError } from 'apollo-link-error'
import { RestLink } from 'apollo-link-rest'
const cache = new InMemoryCache()
const httpLink = new createHttpLink({
credentials: 'include',
})
const restLink = new RestLink({
endpoints: {
localhost: {
uri: "http://localhost:8080"
}
},
credentials: 'include'
})
const errorLink = onError(({ graphQLErrors, networkError, operation }) => {
if (graphQLErrors) {
graphQLErrors.forEach(({ message, locations, path }) => {
console.log(`[GraphQL error] Message: ${message}, ${path}`)
})
}
if (networkError) {
console.log(
`[Network error ${networkError}] Operation: ${operation.operationName}`
)
}
})
export const client = new ApolloClient({
link: ApolloLink.from([errorLink, restLink, httpLink]),
cache,
})
然后我有我的查询:
const LOGIN_QUERY = gql`
mutation doLogin($username: String!, $password: String!, $formSerializer: any) {
user(input: { username: $username, password: $password})
@rest(
path: "/login"
type: "user"
method: "POST"
endpoint: "localhost"
bodySerializer: $formSerializer
) {
id
name
}
}`
const formSerializer = (data, headers) => {
const formData = new URLSearchParams()
for (let key in data) {
if (data.hasOwnProperty(key)) {
formData.append(key, data[key])
}
}
headers.set('Content-Type', 'application/x-www-form-urlencoded')
return { body: formData, headers }
}
我发现文档没有关于如何发送表单数据的示例,这让我非常疯狂,我不得不 google 做了很多,直到我找到了如何做。
然后我在登录组件中执行查询:
const [doLogin, { data }] = useMutation(LOGIN_QUERY, {
onCompleted: () => {
console.log("Success")
},
onError: () => {
console.log("Poop")
}
})
const handleSubmit = (event) => {
event.preventDefault()
console.log('logging in...')
doLogin({
variables: { username, password, formSerializer },
})
}
服务器让我登录,returns 一个会话 cookie,以及一个包含以下内容的正文:
{
"data": {
"user": {
"id": 1
"name": "Foobar"
}
}
}
当我使用 ApolloClient google chrome 插件检查缓存状态时,缓存有:
user:null
id: null
name: null
所以这是我的问题:
- 我需要设置默认状态吗?
- 文档仅显示首次查询对象的突变,如果对象已存在于缓存中,我能否仅使用突变更新缓存?
- 我需要为每种类型编写解析器吗?
- 还有,为什么我得到空值?
- 是否所有数据都需要包装在一个
data
对象中返回,即使对于 rest 查询也是如此? - 必须将
formSerializer
作为变量传递给查询,因为我发现它非常丑陋。
如前所述...ApolloClient 文档是我读过的最糟糕的文档之一。一点都不友好。
根据 Response transforming,apollo 期望来自 REST API 的响应如下:
{
"id": 1,
"name": "Apollo"
}
如果你无法控制后端,你可以使用自定义的响应转换器:
responseTransformer: async response => response.json().then(({data}) => data.data?.user)