如何在执行多个 Apollo 查询和突变后更新本地状态?
How to update local state after the execution of multiple Apollo queries and mutations?
我是 Apollo 的新手,我错过了一些东西。
我有一个查询来获取当前登录的用户,当页面加载时我 运行 并且它是从我最顶级的组件之一执行的(同一个组件也包含反应路由器的匹配逻辑):
export const GET_USER = gql`
query {
me {
id
email
}
}
`
然后非常嵌套在 DOM 树中,我有登录和注销按钮,它们都会触发将要为当前用户设置或取消设置会话的更改。
但是...此时如何更新应用程序顶部的状态?
我已阅读 this blog post 建议将 Apollo Hooks 包装到其他自定义挂钩中:
const useAuth = () => {
const { data: getUserData } = useQuery(GET_USER)
const [login, { data: loginData } = useMutation(LOGIN)
const [logout, { data: logoutData } = useMutation(LOGOUT)
// Should I find out here if I have a user id or not?
// It's doable, but not clean
return { login, logout, userId }
}
以这种方式发出请求对我来说非常不直观,我很容易理解在 Redux 或 MobX 操作中产生这些副作用...因此我打算直接从那里使用 Apollo 客户端,即使这不是 Apollo 文档中建议的解决方案。
我哪里不对?
在我的应用中,我使用 apollo-cache-inmemory
来管理应用状态。我的应用程序是真实状态的单一来源,它看起来像 redux。当你想在 Apollo 状态下操作数据时,你应该使用 useQuery
来查询客户端的数据,使用 useMutation
来更新 Apollo 状态。您可以在 Apollo here.
中阅读有关如何与缓存数据交互的更多信息
这是一个例子:
在 client.js
:
import { InMemoryCache } from 'apollo-cache-inmemory';
import { HttpLink } from 'apollo-link-http';
import { ApolloClient } from 'apollo-client';
const client = new ApolloClient({
link: new HttpLink(),
cache: new InMemoryCache(),
resolvers: {
Mutation: {
setSearchText : (_, { searchValue }, {cache}) => {
cache.writeData({
data: {
searchText: searchValue,
},
})
}
}
}
});
const initialState = {
searchText: ''
}
cache.writeData({ data: initialState})
在SearchBox.js
import React from 'react'
import { useQuery, useMutation } from '@apollo/react-hooks'
import gql from 'graphql-tag'
const SET_SEARCH_TEXT = gql`
mutation SetSearchText($searchValue: String!) {
setSearchText(searchValue: $searchValue) @client
}
`
const GET_SEARCH_TEXT = gql`
query SearchText {
searchText @client
}
`
const SearchBox = () => {
const { data: searchTextData, loading, error } = useQuery(GET_SEARCH_TEXT)
const [setSearchText] = useMutation(SET_SEARCH_TEXT)
const [value, setValue] = React.useState(searchTextData.searchText || '')
handleChange = (e) => {
setValue(e.target.value)
}
onSubmit = () => {
setSearchText({variables: { searchValue: value }}).then(data => console.log(data))
}
return (
<div>
<input type="text" value={value} onChange={handleChange} />
<button onClick={onSubmit}>Submit</button>
</div>
)
}
它将如下所示。重要的部分是突变一旦收到响应就会调用更新函数。那是您手动更新缓存的位置。目标是替换 apollo 缓存中 "me" 的值。令人满意的部分是,一旦你让它工作,从 useQuery 检索的数据将自动更新(因此使用这个钩子重新渲染组件)。这是 link 到 documentation.
const useAuth = () => {
const { data: getUserData } = useQuery(GET_USER)
const [mutateLogin] = useMutation(LOGIN)
const [mutateLogout] = useMutation(LOGOUT)
function login(..args) {
mutateLogin({
variables: args,
update(proxy, {data}) {
proxy.writeQuery({
query: GET_USER,
data: {
me: (GET USER FROM data)
}
})
}
})
}
function logout() {
mutateLogout({
update(proxy, {data}) {
proxy.writeQuery({
query: GET_USER,
data: {
me: null
}
});
}
})
}
return { login, logout, userId }
}
我是 Apollo 的新手,我错过了一些东西。 我有一个查询来获取当前登录的用户,当页面加载时我 运行 并且它是从我最顶级的组件之一执行的(同一个组件也包含反应路由器的匹配逻辑):
export const GET_USER = gql`
query {
me {
id
email
}
}
`
然后非常嵌套在 DOM 树中,我有登录和注销按钮,它们都会触发将要为当前用户设置或取消设置会话的更改。 但是...此时如何更新应用程序顶部的状态?
我已阅读 this blog post 建议将 Apollo Hooks 包装到其他自定义挂钩中:
const useAuth = () => {
const { data: getUserData } = useQuery(GET_USER)
const [login, { data: loginData } = useMutation(LOGIN)
const [logout, { data: logoutData } = useMutation(LOGOUT)
// Should I find out here if I have a user id or not?
// It's doable, but not clean
return { login, logout, userId }
}
以这种方式发出请求对我来说非常不直观,我很容易理解在 Redux 或 MobX 操作中产生这些副作用...因此我打算直接从那里使用 Apollo 客户端,即使这不是 Apollo 文档中建议的解决方案。
我哪里不对?
在我的应用中,我使用 apollo-cache-inmemory
来管理应用状态。我的应用程序是真实状态的单一来源,它看起来像 redux。当你想在 Apollo 状态下操作数据时,你应该使用 useQuery
来查询客户端的数据,使用 useMutation
来更新 Apollo 状态。您可以在 Apollo here.
中阅读有关如何与缓存数据交互的更多信息
这是一个例子:
在 client.js
:
import { InMemoryCache } from 'apollo-cache-inmemory';
import { HttpLink } from 'apollo-link-http';
import { ApolloClient } from 'apollo-client';
const client = new ApolloClient({
link: new HttpLink(),
cache: new InMemoryCache(),
resolvers: {
Mutation: {
setSearchText : (_, { searchValue }, {cache}) => {
cache.writeData({
data: {
searchText: searchValue,
},
})
}
}
}
});
const initialState = {
searchText: ''
}
cache.writeData({ data: initialState})
在SearchBox.js
import React from 'react'
import { useQuery, useMutation } from '@apollo/react-hooks'
import gql from 'graphql-tag'
const SET_SEARCH_TEXT = gql`
mutation SetSearchText($searchValue: String!) {
setSearchText(searchValue: $searchValue) @client
}
`
const GET_SEARCH_TEXT = gql`
query SearchText {
searchText @client
}
`
const SearchBox = () => {
const { data: searchTextData, loading, error } = useQuery(GET_SEARCH_TEXT)
const [setSearchText] = useMutation(SET_SEARCH_TEXT)
const [value, setValue] = React.useState(searchTextData.searchText || '')
handleChange = (e) => {
setValue(e.target.value)
}
onSubmit = () => {
setSearchText({variables: { searchValue: value }}).then(data => console.log(data))
}
return (
<div>
<input type="text" value={value} onChange={handleChange} />
<button onClick={onSubmit}>Submit</button>
</div>
)
}
它将如下所示。重要的部分是突变一旦收到响应就会调用更新函数。那是您手动更新缓存的位置。目标是替换 apollo 缓存中 "me" 的值。令人满意的部分是,一旦你让它工作,从 useQuery 检索的数据将自动更新(因此使用这个钩子重新渲染组件)。这是 link 到 documentation.
const useAuth = () => {
const { data: getUserData } = useQuery(GET_USER)
const [mutateLogin] = useMutation(LOGIN)
const [mutateLogout] = useMutation(LOGOUT)
function login(..args) {
mutateLogin({
variables: args,
update(proxy, {data}) {
proxy.writeQuery({
query: GET_USER,
data: {
me: (GET USER FROM data)
}
})
}
})
}
function logout() {
mutateLogout({
update(proxy, {data}) {
proxy.writeQuery({
query: GET_USER,
data: {
me: null
}
});
}
})
}
return { login, logout, userId }
}