redux-toolkit: RTK Query - Cache invalidation after HTTP Delete causes 404

I have the following example api slice:

const postService = apiService.injectEndpoints({
  endpoints: (builder) => ({
    fetchPosts: builder.query({
      query: () => `/posts`,
      providesTags: (result = [], error, arg) => [
        "Posts",
        ...result.map(({ id }) => ({ type: "Posts", id })) 
      ],  
    }), 
    getPost: builder.query({
      query: post => `/posts/${post.id}`,
      providesTags: (result, error, arg) => [{ type: "Posts", id: post.id }]
    }), 
    addPost: builder.mutation({
      query: (data) => ({
        url: `/posts`,
        method: "POST",
        body: data.payload
      }), 
      invalidatesTags: [SHIFTS]
    }), 
    updatePost: builder.mutation({
      query: (post) => ({
        url: `/posts/${post.id}`,
        method: "PATCH",
        body: post
      }), 
      invalidatesTags: (result, error, arg) => [{ type: "Posts", id: post.id }]
    }), 
    deletePost: builder.mutation({
      query: (post) => ({
        url: `"/posts/${post.id}`,
        method: "DELETE"
      }), 
      invalidatesTags: (result, error, arg) => [{ type: "Posts", id: post.id }]
    }), 
  }), 
  overrideExisting: false,
})

If a user views a post, the useGetPostQuery hook is run and the post is fetched with tag { type: "Posts", id: post.id }. Immediately after, if a user deletes the same post, this invalidates the cache for posts and the specific /posts/${post.id} GET, causing a refetch of the /posts/${post.id} resource which 404s because the resource no longer exists.

  1. GET /posts/1
  2. DELETE /posts/1
  3. RTK Query -> GET /posts/1 -> 404

Is there a way to prevent this? I still need the delete to invalidate the fetchAll cache so users can see updates on screen when deleting.

About this issue

  • Original URL
  • State: closed
  • Created 3 years ago
  • Comments: 17 (3 by maintainers)

Most upvoted comments

@phryneas Hi,

I face the same issue as @fvkramer but I do not understand your conclusion. Changing the invalidatesTags of the deletePost mutation will avoid automated re-fetch however the previous getPost with tag { type: "Posts", id: post.id } is still in cache.

In my case, I have the Post delete action in a Post details page. When I press the delete Post button I’m redirected to the Post list. So if I browse to a specific Post (eg post/2), trigger delete then press the browser back button, the intial Post query (eg post/2) is still in cache and page is still reachable.

I tried to play with skipToken to avoid query if mutation isLoading but it doesn’t work cause RTK query still consider the subscription as active. I do not find documentation on how to manually unsubscribe from subscription created with a generated hook.

I’d like some guidance on that because delete action isn’t well documented and it’s a classic behavior IMO.

@ctjhoa

Hi,

I have caught same issue and I was only able to clear the cache manually. RTK-doc

const {data: {ID}} = useGetDataQuery(undefined)
const {deletItem} = usePostDeleteMutation()
...
const handleDelete = async (id) => {
    await deletItem(id)
    dispatch(
        api.util.updateQueryData(
            'useGetDataQuery',
            undefined,
            (draft) => (
                Object.assign(draft, {ID: undefined})
            )
       )
    )
}

Hey, @korneSt! Have you managed to figure it out? Your approach with skipfetch flag is working for me. But I’m still looking for a solution to unsubscribe after deletion

My problematic use-case:

I have a list of items and option to click on it to open details in the modal with delete button in there. The tags we provide are something like this:

getList => provides 'Contact'
getListItem => provides 'Contact'
addListItem => invalidates 'Contact'
deleteListItem => invalidates 'Contact'

So bascially we don’t use tags with sepcific Id. When we udpate ListItem, we update single item and the whole list. But when I try to delete ListItem, RTK Query tries to invalidate already removed item that causes 404.

To fix that I added Tag {type: 'Contact', id: 'LIST'} to the getList endpoint and invalidate only that on delete. So like this

getList => provides ['Contact', {type: 'Contact', id: 'LIST'}]
getListItem => provides 'Contact'
addListItem => invalidates 'Contact'
deleteListItem => invalidates {type: 'Contact', id: 'LIST'}

This way on delete I only refetch list of items with getList query. It works now. However when I deleted item #1 and revalidate the ‘LIST’, cache from getListItem(#1) is still there (Contact tag).

So when I later create a new item, it invalidates ‘Contact’ tag and tries to fetch item with deleted id (#1).