Jason Saelhof
Jason Saelhof

Reputation: 98

Apollo useLazyQuery hook uses old variables when refetching (instead of new vars)

My database stores a list of items. I've written a query to randomly return one item from the list each time a button is clicked. I use useLazyQuery and call the returned function to execute the query and it works fine. I can call the refetch function on subsequent button presses and it returns another random item correctly.

The problem comes when i try to pass variables to the query. I want to provide different criteria to the query to tailor how the random choice is made. Whatever variables I pass to the first call are repeated on each refetch, even though they have changed. I can trace that they are different on the client but the resolver traces the previous variables.

// My query
const PICK = gql`
  query Pick($options: PickOptionsInput) {
    pick(options: $options) {
      title
    }
  }
`;

// My lazy hook
const [pick, { data, refetch }] = useLazyQuery(PICK, {
    fetchPolicy: "no-cache",
  });


// My button
<MyButton
  onPick={(options) =>
     (refetch || pick)({ // Refetch unless this is the first click, then pick
         variables: {
            options      // Options is a custom object of data used to control the pick
         },
     })
  }
/>

Some things I've tried:

I'm really stumped. It seems like the docs say new variables are supposed to be used if they are provided on refetch. I don't think the cache policy is relevant...I'm getting fresh results on each call, it's just the input variables that are stale.

Upvotes: 3

Views: 3452

Answers (1)

xadm
xadm

Reputation: 8418

I guess only pick is called ...

... because for <MyBytton/> there is no props change, no onPick redefined - always the first handler definition used (from first render) and options state from the same time ...

Try to pass all (options, pick and refetch) as direct props to force rerendering and handler redefinition:

<MyButton
  options={options}
  pick={pick}
  refetch={refetch}
  onPick={(options) =>
     (refetch || pick)({ // Refetch unless this is the first click, then pick
         variables: {
            options      // Options is a custom object of data used to control the pick
         },
     })
  }
/>

... or [better] define handler before passing it into <MyButton/>:

const pickHandler = useCallback( 
  (options) => {
     if(refetch) {
       console.log('refetch', options);
       refetch( { variables: { options }});
     } else {
       console.log('pick', options);
       pick( { variables: { options }});
     }
  },
  [options, pick, refetch]
);

<MyButton onPick={pickHandler} />

Upvotes: 2

Related Questions