profile
viewpoint

Ask questionsuseLazyQuery execution function should return a promise

People don't know if they should use a query or a mutation to login an user when that login performs no side-effect (ie, just query for an auth token).

https://stackoverflow.com/questions/50189364/shouldnt-the-login-be-a-query-in-graphql

But Apollo users tend to currently use mutations because they want the operation to execute only after user press a submit button.

Recently a new useLazyQuery was added (by @FredyC I think?), and it could be useful to solve this problem: keep a query, but actually execute it after user press a button.

Unlike mutations, it does not return a promise when executed.

I suggest the following should be possible:

image

edit: actually the screenshot is wrong but you probably understand the point of returning a promise instead of void here (at least in TS typings)

Note other apis do return a promise when called (see "refetch" for example). I think useLazyQuery should follow the exact same convention and not return void.

apollographql/react-apollo

Answer questions FredyC

And I just came to a realization that the Promise should not be rejected at all. Mainly because it's usually redundant as an error will appear in the result itself and can be handled more gracefully in a render phase. The rejected promise is impossible to be caught by any React mechanism (error boundary) and would need to be handled per each case on the call site, otherwise, the annoying unhandledRejection would appear in logs.

In my opinion, it's enough if the Promise resolves with the whole result object when "loading" is done.

Perhaps that's something to consider for a real implementation later.

export function useLazyQuery<TData = any, TVariables = OperationVariables>(
  query: DocumentNode,
  options?: LazyQueryHookOptions<TData, TVariables>,
): LazyQueryHookTuple<TData, TVariables> {
  const [execute, result] = Hooks.useLazyQuery<TData, TVariables>(query, options)

  const resolveRef = React.useRef<
    (value?: LazyQueryResult<TData>| PromiseLike<LazyQueryResult<TData>>) => void
  >()

  React.useEffect(() => {
    if (result.called && !result.loading && resolveRef.current) {
      resolveRef.current(result)
      resolveRef.current = undefined
    }
  }, [result.loading, result.called])

  const queryLazily: LazyQueryExecute<TData, TVariables> = React.useCallback(
    (variables, context) => {
      execute({ variables, context })
      return new Promise<LazyQueryResult<TData>>((resolve) => {
        resolveRef.current = resolve
      })
    },
    [execute],
  )

  return [
    queryLazily,
    result
  ]
}

useful!
source:https://uonfu.com/
Github User Rank List