Apollo client queries and data store when connected to multiple components
Asked Answered
E

1

6

I have 3 different components that use the same graphql query. This example would be GET_USERS query. This is used when looking for users to message in the messaging respective tab and also when inviting users for actions and tagging them when creating posts.

the problem I'm having and trying to figure out how to handle is that its not always the case that only one is rendered at a time. A user might click the message tab and then go to tag a user in the post tab. Problem: when he comes back to the message tab it now has re-rendered with the state of the query that was called from the tagging.

Any suggestions on how to set up the state with Apollo and the queries in general to avoid this issue. At the end of the day my backend is one "route" or resolve function for the specific action.

EDIT For further information. The way I know I could solve it is to use axios request to the graphql endpoint and store the response in local useState for that component. If I did this for each of the different places in the app that use the information they would remain decoupled and not share the exact same state.

But to be clear I am trying to solve this while using Apollo if possible.

Estelleesten answered 11/1, 2021 at 5:27 Comment(1)
simply use cache-only fetchPolicy in queries/components you want to not affect 'main source of truth' ?Bereniceberenson
G
6

You could use a combination of local state (useState) and useLazyQuery. From what I understand you have multiple components (or screens, tabs, whatever) mounted at the same time, say ScreenA and ScreenB. In each of them you query GET_USERS, but when your query results update in ScreenB, you don't want to also update the results in ScreenA.

With useLazyQuery this could look like this:

  1. Create a custom hook for easy reusability across components
export const useLazyGetUsers = () => {
  const [users, setUsers] = useState()

  const [queryGetUsers] = useLazyQuery(GET_USERS, {
    onCompleted: (data) => setUsers(data.users),
    onError: (error) => console.log('onError', { error }), // handle errors as you wish
    fetchPolicy: "cache-and-network", // or whatever you want
  })

  return {queryGetUsers, users}
}
  1. In ScreenA, use the hook and fetch the query:
const ScreenA = () => {
  const {queryGetUsers, users} = useLazyGetUsers()
  
  return (
    <TouchableOpacity onPress={() => queryGetUsers()}>
      <Text>Get users</Text>
    </TouchableOpacity>
  )
}
  1. In ScreenB, also use the hook.

Note that you can call queryGetUsers whenever you want, on mount, on TouchableOpacity press, or whenever.

const ScreenB = () => {
  const {queryGetUsers, users} = useLazyGetUsers()
  
  useEffect(() => {
    queryGetUsers()
  }, [])

  return (
    ...
  )
}
  1. Use users as you wish. If you call queryGetUsers in ScreenA, it will not update the value of users in ScreenB.

This is not a 100% Apollo solution but it makes minimal use of local state and the hooks makes it very easy to reuse. I hope this solves your issue!

You can read more about useLazyQuery here:

Godden answered 20/1, 2021 at 10:10 Comment(2)
Do you know how to resolve the same issue when we have not separated but the map of the same reusable component? screens.map(screen => < ScreenA />)Haemato
@Haemato not sure what you are talking about. Maybe post a question with more details and tag it here, then I can take a look.Godden

© 2022 - 2024 — McMap. All rights reserved.