Is it possible to prevent `useLazyQuery` queries from being re-fetched on component state change / re-render?
Solution 1
The react-apollo
documentation doesn't mention whether useLazyQuery
should continue to fire the query when variables change, however they do suggest using the useApolloClient
hook when you want to manually fire a query. They have an example which matches this use case (clicking a button fires the query).
function DelayedQuery() {
const [dog, setDog] = useState(null);
const client = useApolloClient();
return (
<div>
{dog && <img src={dog.displayImage} />}
<button
onClick={async () => {
const { data } = await client.query({
query: GET_DOG_PHOTO,
variables: { breed: 'bulldog' },
});
setDog(data.dog);
}}
>
Click me!
</button>
</div>
);
}
Solution 2
You don't have to use async
with the apollo client (you can, it works). But if you want to use useLazyQuery
you just have to pass variables on the onClick
and not directly on the useLazyQuery call.
With the above example, the solution would be:
function DelayedQuery() {
const [dog, setDog] = useState(null);
const [getDogPhoto] = useLazyQuery(GET_DOG_PHOTO, {
onCompleted: data => setDog(data.dog)
})
return (
<div>
{dog && <img src={dog.displayImage} />}
<button
onClick={() => getDogPhoto({ variables: { breed: 'bulldog' }})}
>
Click me!
</button>
</div>
);
}
user11754604
Updated on June 05, 2022Comments
-
user11754604 almost 2 years
Currently I have a
useLazyQuery
hook which is fired on a button press (part of a search form).The hook behaves normally, and is only fired when the button is pressed. However, once I've fired it once, it's then fired every time the component re-renders (usually due to state changes).
So if I search once, then edit the search fields, the results appear immediately, and I don't have to click on the search button again.
Not the UI I want, and it causes an error if you delete the search text entirely (as it's trying to search with
null
as the variable), is there any way to prevent theuseLazyQuery
from being refetched on re-render?This can be worked around using
useQuery
dependent on a 'searching' state which gets toggled on when I click on the button. However I'd rather see if I can avoid adding complexity to the component.const AddCardSidebar = props => { const [searching, toggleSearching] = useState(false); const [searchParams, setSearchParams] = useState({ name: '' }); const [searchResults, setSearchResults] = useState([]); const [selectedCard, setSelectedCard] = useState(); const [searchCardsQuery, searchCardsQueryResponse] = useLazyQuery(SEARCH_CARDS, { variables: { searchParams }, onCompleted() { setSearchResults(searchCardsQueryResponse.data.searchCards.cards); } }); ... return ( <div> <h1>AddCardSidebar</h1> <div> {searchResults.length !== 0 && searchResults.map(result => { return ( <img key={result.scryfall_id} src={result.image_uris.small} alt={result.name} onClick={() => setSelectedCard(result.scryfall_id)} /> ); })} </div> <form> ... <button type='button' onClick={() => searchCardsQuery()}> Search </button> </form> ... </div> ); };