react-apollo-hooks icon indicating copy to clipboard operation
react-apollo-hooks copied to clipboard

How to handle dynamic variables in useQuery?

Open rsjolundchas opened this issue 6 years ago • 22 comments

Started fiddeling with this package and it looks really awsome. I am trying to understand how to automatically refetch when variables changes in a useQuery hook. I don't know if i misunderstood something but this is what I have tried, and it only fetches once.`

On first render, it fetches correctly and logs correct data and variables. When setVariables it runs it updates those correctly, but no re-render is done and it logs new variables but same old data. Am i missing something here? There is no example for this.

function foo() {
  const [variables, setVariables] = useState({});
  const { data, loading } = useQuery(SOME_GRAPHQL_SCHEMA, {
    variables,
    suspend: false,
  });

  if(loading) return <p>Loading</p>;
  console.log(data, variables);
  return (...);
}
```

rsjolundchas avatar Feb 15 '19 10:02 rsjolundchas

This seems to work, but I don't really know if its the right approach.

function foo() {
  const [variables, setVariables] = useState({});
  const { data, loading } = useQuery(SOME_GRAPHQL_SCHEMA, {
    variables,
    suspend: false,
  });

  useEffect(() => {
    refetch(variables);
  }, [variables]);


  if(loading) return <p>Loading</p>;
  console.log(data, variables);
  return (...);
}

rsjolundchas avatar Feb 15 '19 10:02 rsjolundchas

@rsjolundchas the first example should work. Please look at https://codesandbox.io/s/n4o02oz6jm - you should see different images for cats and dogs.

trojanowski avatar Feb 15 '19 11:02 trojanowski

Thanks for your reply. I came up with a different approach to prevent having to set JSX based on loading props, which seems messy to me. I instead made a custom hook to handle data fetching, mutations and variables, and am going to try to also implement cache updates in it, which i hope works and is a bit cleaner to me :)

rsjolundchas avatar Feb 19 '19 08:02 rsjolundchas

I'm having issues with this also:

const [sortOptions, openSortBottomSheet] = useSortOptions<CollectibleTypeSortOptions>('STORE_BROWSE')
  const {
    data,
    networkStatus,
    refetch,
    fetchMore,
    loading
  } = useQuery<StoreBrowseQuery, StoreBrowseQueryVariables>(QUERY, {
    notifyOnNetworkStatusChange: true,
    variables: sortOptions
  })

Event though the value of sortOptions changes the query never refetches. Seems like something is missing

bsunderhus avatar Apr 03 '19 12:04 bsunderhus

I ended up giving up just using useApolloClient() (which actually makes more sense in my case),

rsjolundchas avatar Apr 04 '19 05:04 rsjolundchas

I'm having the same problem. If the variables change the query is not re-executed. Any help would be appreciated

fgiarritiello avatar Jun 14 '19 22:06 fgiarritiello

I ended up using useEffect and refetch() when variables change. Don't know if this is the right approach.

rsjolundchas avatar Jun 24 '19 05:06 rsjolundchas

@rsjolundchas how did you use refetch() excatly?

vidur149 avatar Jul 10 '19 07:07 vidur149

@rsjolundchas how did you use refetch() excatly?

Like in my post above

This seems to work, but I don't really know if its the right approach.

function foo() {
  const [variables, setVariables] = useState({});
  const { data, loading } = useQuery(SOME_GRAPHQL_SCHEMA, {
    variables,
    suspend: false,
  });

  useEffect(() => {
    refetch(variables);
  }, [variables]);


  if(loading) return <p>Loading</p>;
  console.log(data, variables);
  return (...);
}

rsjolundchas avatar Jul 10 '19 12:07 rsjolundchas

got it, idk how I missed this comment. Thanks.

Also, I have a completely unrelated doubt how are you comparing variables if they are an object. I am talking about how to actually deep compare the dependencies of useState, RN i run into an infinite loop. So, I used JSON.stringify.

@rsjolundchas

vidur149 avatar Jul 10 '19 15:07 vidur149

I think I ended up looking at parts of the object actually. I am at i new assignment right now so i can't check. But something like:

useEffect(() => {
    refetch(variables);
  }, [variables.limit, variables.order, variables.filter]);

rsjolundchas avatar Jul 11 '19 11:07 rsjolundchas

Is there any traction on this issue? Just started hitting it today...

noah79 avatar Aug 16 '19 14:08 noah79

Here's my hacky workaround:

/**
 * When the variables inside options changes dynamically, the query is NOT rerunning as of react-apollo beta.5
 * See https://github.com/trojanowski/react-apollo-hooks/issues/83
 *
 * We add a useEffect here to refetch the query if the underlying variables change
 * @param query
 * @param options
 */
export function useQueryDynamic<TData = any, TVariables = OperationVariables>(query: DocumentNode, options?: QueryHookOptions<TData, TVariables>): QueryResult<TData, TVariables> {
  const isFirstRun = useRef(true);
  const q          = useQuery(query, options)

  useEffect(() => {
    if (!isFirstRun.current) {
      q.refetch()
    } else isFirstRun.current = false
  }, [JSON.stringify(options.variables)])

  return q
}

noah79 avatar Aug 16 '19 15:08 noah79

Hitting this as well, and I hit the useEffect/refetch issue (infinite fetching), so this is a bug then? I thought I was going crazy

Anahkiasen avatar Aug 28 '19 12:08 Anahkiasen

Hitting this as well, and I hit the useEffect/refetch issue (infinite fetching), so this is a bug then? I thought I was going crazy

How does your code look? I made the mistake of storing the variables in the function body and then check them in useEffect(). Since they where defined every re-render, the effect ran each re-render and created an infinite loop.

rsjolundchas avatar Aug 29 '19 06:08 rsjolundchas

This works for me: const { loading, error, data } = useQuery(QUERY_SCHEMA, {variables: {var1:value1}})

dmayo2 avatar Sep 27 '19 19:09 dmayo2

Hi,

Encountered this too. Issue of setting the value of title did not cause a re-query of the API.

Here is the way I was able to resolve.

Before (not work):

const BOOKS_QUERY = gql`
  {
    books {
      author
      title
    }
  }
`;

// note, the below lines of code are in the React function
const [title, setTitle] = useState("");

const { loading, error, data } = useQuery(BOOKS_QUERY, {
    variables: { title }
  });

Resolution (works!) - modified the query:

const BOOKS_QUERY = gql`
  query getBooks($title: String) {
    books(title: $title) {
      author
      title
    }
  }
`;

And then was able to achieve the desired outcome.

EricGrudzien avatar Oct 04 '19 20:10 EricGrudzien

Just ran in to this problem myself and noticed a similar issue to @EricGrudzien above. My variable name was wrong when passing in to the query:

const { data, loading } = useQuery<SearchClientsResponse>(SEARCH, { variables: { keywords, sort }, });

But by query definition was:

query SearchClients($keywords: String, $sortBy: String) {
    searchClients(keywords: $keywords, sortBy: $sortBy) {
     id
    }

sort should have been sortBy 😆

dejanvasic85 avatar May 07 '20 11:05 dejanvasic85

Still having this issue

hyposlasher avatar Jan 27 '22 10:01 hyposlasher

@hyposlasher did you notice the part where this library is super deprecated? -- there are official react hooks for ApolloClient that you should really move to! https://www.npmjs.com/package/@apollo/react-hooks

fbartho avatar Jan 27 '22 18:01 fbartho

I believe this is what you're looking for. You need to add those variables in the query key.

natBizitza avatar Jul 12 '23 09:07 natBizitza

I believe this is what you're looking for. You need to add those variables in the query key.

The link you provided is for React Query, which has no relation to Apollo.

christopher-caldwell avatar Sep 05 '23 22:09 christopher-caldwell