Kamil P
Kamil P

Reputation: 784

react-query - getQueryData and setQueryData with pagination

I have some resource, let's call it todos.

I have list of it and user can delete on from list.

Before I implemented paginaiton that was looking like

const {data} = useQuery('todos', fetchTodos)

and in other place where I'm deleting it

  const [deleteTodo, deletingMutation] = useMutation(
    (id) => deleteTodo(id),
    {
      onSuccess: (data, deletedTodoId) => {
        const { todos } = queryCache.getQueryData<any>('todos');

        queryCache.setQueryData('todos', {
          todos: todos.filter(todo=>todo.id !== deletedTodoId),
        });
      },
    });

so in other place I'm just modyfing this data set called 'todos'

but After I implemented paginaiton things are more complicated because QueryKey isn't now just 'todos' but it's ['todos', page]

so when I'm deleting todo and calling in onSuccess this code queryCache.getQueryData<any>('todos');, it returns me undefined - because QueryKey contains additionally this page number.

How should I resolve it? Modyfing query data with paginated QueryKey.

Upvotes: 8

Views: 13211

Answers (3)

alex-jesper
alex-jesper

Reputation: 113

The setQueriesData(...) seems to be intended for exactly that purpose:

setQueriesData is a synchronous function that can be used to immediately update cached data of multiple queries by using filter function or partially matching the query key.

So if you call setQueriesData with just the "todo" key I assume it will update all of them.

Thanks, Jesper

Upvotes: 0

David Lefarth
David Lefarth

Reputation: 76

I think I'm too late for you but i had the same problem and want to share my solution (although it's a little bit hacky)

I wrote a function which returns all the related cache keys

const getRelatedCacheKeys = (queryClient, targetKey) => {
  return queryClient.getQueryCache().getAll()
    .map(query => query.queryKey)
    .filter(key => Array.isArray(key) ? key.includes(targetKey) : key === targetKey)
}

Then I call the setQueryData function for all related keys.

 onSuccess: data => {
   const keys = getRelatedCacheKeys(queryClient, 'key')
   keys.forEach(key => {
     queryClient.setQueryData(key, old => updateFn(old, data))
   })
 }

But the option to simply invalidate the cache seems tp be more practical

onSuccess: () => queryClient.invalidateQueries('key')

With this solution, all related keys also get invalidated

Upvotes: 4

MeltedPenguin
MeltedPenguin

Reputation: 797

To answer your question directly, you can provide a more specific key to getQueryData:

queryCache.getQueryData<any>(['todos', page]);

Be aware that manually deleting in a pagination will create shift issues:

const paginatedTodos = [ [1, 2], [3, 4], [5, 6] ];
deleteTodoId(3);
// you would get [ [1, 2], [4], [5, 6] ]
// instead of    [ [1, 2], [4, 5], [6] ]

You could try to fix the "hole" in the page, but to avoid any inconsistencies it may be better to simply invalidate all of the todos queries to resynchronize with the actual data on your server.

Upvotes: 1

Related Questions