执行多个Apollo查询和变异后如何更新本地状态?

时间:2020-05-26 23:12:37

标签: reactjs graphql react-apollo apollo-client

我是阿波罗(Apollo)的新手,但我缺少一些东西。 我有一个查询来获取页面加载时运行的当前登录用户,并且该查询是从我最重要的组件之一执行的(同一组件还包含react-router的匹配逻辑):

export const GET_USER = gql`
  query {
    me {
      id
      email
    }
  }
`

然后非常嵌套在DOM树中,我有登录和注销按钮,这两个按钮都会触发突变,这些突变将为当前用户设置或取消设置会话。 但是...此时我该如何更新应用顶部的状态?

我已阅读this blog post,建议将Apollo挂钩包装到其他自定义挂钩中:

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文档中建议的解决方案。

我不正确是什么?

2 个答案:

答案 0 :(得分:1)

如下所示。重要的是,突变一旦收到响应,便调用更新功能。那是您手动更新缓存的位置。目标是替换阿波罗缓存中的“ me”值。令人满意的部分是,一旦您开始工作,从useQuery检索的数据将自动更新(因此,使用此挂钩重新渲染组件)。这是指向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 }
}

答案 1 :(得分:0)

在我的应用程序中,我使用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>
  )
}