trojanowski / react-apollo-hooks

Use Apollo Client as React hooks
MIT License
2.41k stars 109 forks source link

useQuery does not return data on refetch after error. #74

Open rostero1 opened 5 years ago

rostero1 commented 5 years ago

Steps to reproduce:

  1. Make a successful request
  2. Take graphql server offline
  3. Make a new request
  4. We get an error now.
  5. Take graphql server online
  6. Invoke refetch.
  7. Note the successful network request in devtools, but we never get data back from useQuery.
maxguzenski commented 5 years ago

This issue happen on my own apollo hook implementation as well. The solution is re-subscribe to watched query after an error. I believe it is an apollo-client core issue.

useEffect(() => {
  const subscribe = watchedQuery.subscribe({...}) 
  return () => subscribe.unsubscribe()
}, [...othersVariablesToCheck, error]) // <- this
maxguzenski commented 5 years ago

My mistake. Only re-subscribe dont fix this issue https://github.com/apollographql/react-apollo/issues/2070

My work around now is rebuild client.watchQuery after a refetch with error.

maxguzenski commented 5 years ago

I was able to solve the problem based on https://github.com/apollographql/react-apollo/blob/master/src/Query.tsx#L363

changing useEffect inside useQuery by:

  useEffect(() => {
    if (!watchedQuery) {
      return 
    }

    let subscription

    // if fetchPolicy='cache-and-network' and data is on cache
    // notifyOnNetworkStatusChange is aways TRUE, why?? 
    // this "if" fix it.
    function invalidateCurrentResult(props) {
      if (props.loading) return
      setResponseID(x => x + 1)
    } 

    // from: https://github.com/apollographql/react-apollo/blob/master/src/Query.tsx#L363
    // after a error on refetch, without this fix, refetch never works again
    function invalidateErrorResult() {
      unsubscribe()

      const lastError  = watchedQuery.getLastError()
      const lastResult = watchedQuery.getLastResult()

      watchedQuery.resetLastResults()
      subscribe() 

      Object.assign(watchedQuery, { lastError, lastResult })
      setResponseID(x => x + 1)
    }

    function subscribe() {
      subscription = watchedQuery.subscribe(
        invalidateCurrentResult,
        invalidateErrorResult
      )
    }

    function unsubscribe() {
      if (subscription) subscription.unsubscribe() 
      subscription = undefined
    }

    subscribe()
    return unsubscribe

  }, [watchedQuery])
trojanowski commented 5 years ago

@maxguzenski Thank you for the info. Would you like to prepare a PR?

pontusab commented 5 years ago

@maxguzenski Would really want a PR for this too 💯

maxguzenski commented 5 years ago

I'm on vacation until March, 25 ... I can not do a PR until that date.

pontusab commented 5 years ago

@maxguzenski Have a great vacation, I will make a PR with your solution. Thanks 🥇

gregbty commented 5 years ago

I'm assuming a PR is still needed for this? Running into this issue now and it is still unresolved in react-apollo so thought it would probably be easier to apply the workaround above in this repo. I can open one if needed.