trojanowski / react-apollo-hooks

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

How to handle dynamic variables in useQuery? #83

Open rsjolundchas opened 5 years ago

rsjolundchas commented 5 years ago

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 commented 5 years ago

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 (...);
}
trojanowski commented 5 years ago

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

rsjolundchas commented 5 years ago

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 :)

bsunderhus commented 5 years ago

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

rsjolundchas commented 5 years ago

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

fgiarritiello commented 5 years ago

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

rsjolundchas commented 5 years ago

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

vidur149 commented 5 years ago

@rsjolundchas how did you use refetch() excatly?

rsjolundchas commented 5 years ago

@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 (...);
}
vidur149 commented 5 years ago

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

rsjolundchas commented 5 years ago

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]);
noah79 commented 5 years ago

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

noah79 commented 5 years ago

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
}
Anahkiasen commented 5 years ago

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

rsjolundchas commented 5 years ago

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.

dmayo2 commented 4 years ago

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

EricGrudzien commented 4 years ago

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.

dejanvasic85 commented 4 years ago

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 😆

hyposlasher commented 2 years ago

Still having this issue

fbartho commented 2 years ago

@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

natBizitza commented 1 year ago

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

christopher-caldwell commented 1 year ago

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.