7

On my api I have two mutations and strangely, one of them does trigger the refetch but the other doesn't and I have no clue why. Both mutations make their networks calls and changes are reflected in the server.

Here's my api definition.

import { createApi, fetchBaseQuery } from "@reduxjs/toolkit/dist/query/react";
import Sample from "core/types/Sample";
import getApiURL from "core/utils/getApiURL";

export const lithologyApi = createApi({
  baseQuery: fetchBaseQuery({ baseUrl: getApiURL() }),
  tagTypes: ["Samples"],
  endpoints: build => ({
    addSample: build.mutation<Sample, Sample>({
      query: sample => ({
        url: `lithology/add-sample`,
        method: "POST",
        body: sample,
      }),
      invalidatesTags: ["Samples"],
    }),
    getSamples: build.query<Sample[], void>({
      query: () => "lithology/get-samples",
      providesTags: ["Samples"],
    }),
    deleteSample: build.mutation<void, number>({
      query: id => ({ url: `lithology/delete-sample/${id}`, method: "DELETE" }),
      invalidatesTags: ["Samples"],
    }),
  }),
});

export const {
  useAddSampleMutation,
  useGetSamplesQuery,
  useDeleteSampleMutation,
} = lithologyApi;

I don't know if it's relevant but the mutation that succesfully invalidates (addSample) it's in a different component, while the one that doesn't (deleteSample) it's in the same (I've already tried moving it to another component and it didn't work anyways).

Juan De la Cruz
  • 436
  • 6
  • 17
  • Hmm. Generally: change the import to `"@reduxjs/toolkit/query/react"` but that won't solve the problem. Are all of these really in one `createApi` call or did you simplify that for the Stackoverflow question? Also, just to make sure: the middleware is registered? – phry Jun 28 '21 at 16:05
  • Yes, that's all there is for that createApi call and yes, the middleware is registered. I mean, the `deleteSample` mutation callback makes the network request, it just doesn't trigger the invalidation for `getSamples` (which `addSamples` does). – Juan De la Cruz Jun 28 '21 at 17:03
  • 1
    If the middleware were not registered, it would still make the network request, but not trigger invalidation, that's why I was asking. – phry Jun 28 '21 at 18:46
  • Do you get a completely empty response back? And can you check if your mutation actually goes into an `isError` state? I have an assumption. – phry Jun 28 '21 at 19:29
  • Because I was in a hurry, I ended doing things how I was doing them before, so I don't have that code available anymore. I'll definitely try it on with any new project I have and thank you very much for helping :) – Juan De la Cruz Jun 29 '21 at 20:56
  • In my case it was case mentioned by @FooBar, tho I had to add [thunk before this middleware](https://stackoverflow.com/a/62302377/17507134) – Kosti Nov 25 '21 at 11:25

3 Answers3

2

In my case it was related to not adding the middleware to configureStore.

export const lithologyApi = createApi({
// ....
});

const store = configureStore({
    // ....

    // Adding the api middleware enables caching, invalidation, polling,
    // and other useful features of `rtk-query`.
    middleware: [
        lithologyApi.middleware,
    ],
});
FooBar
  • 5,752
  • 10
  • 44
  • 93
1

So, just to give an answer here so that someone else can maybe use it:

I assume that your deleteSample endpoint was giving an empty response. Per default, fetchBaseQuery's responseHandler is set to json, so it tries to JSON.parse an empty string - and crashes with an unhandled error.

Uncaught SyntaxError: JSON.parse: unexpected end of data at line 1 column 1 of the JSON data

Now, invalidateTags is only called on success and for handled errors, but not in the case of an unhandled error, since that would lead to all kinds of inpredictable behaviour in case your invalidateTags was not an array, but a function.

Long story short: In your request, set responseHandler to text or a custom function.

Also, always read errors - when you read that error above getting back from your hook, it should already become pretty obvious :)

phry
  • 35,762
  • 5
  • 67
  • 81
  • This sounds like the most likely case, however I don't remember ever seeing any unhandled error on console. I'll try testing if this is the case and I wonder if it might be useful to change parts of the question to match more specifically the problem, so people find it easier. – Juan De la Cruz Jun 29 '21 at 23:45
  • Even unhandled, it would end up in the `error` field of the hook, not on the console. – phry Jun 30 '21 at 07:07
  • This helped me on my issue on using SWAPI's wookie format. Indeed, the `responseHandler` does a `JSON.parse` under the hood. And in my case, I am using ngrx-rtk-query for my ng project. When the handler fails to parse the data, error is caught internally and `transformResponse` is simply not invoked. – Alex Pappas Aug 17 '21 at 11:37
  • Updating to Redux Toolkit 1.6.1 should give you a much more descriptive error and any unhandled error will also be printed to the console. – phry Aug 17 '21 at 12:52
0

Try adding the next function to the file and replace the providedTags in getSamples query function.

const providesTags = (result: ReportPinsResponse | undefined) => {
  if (result && result.items) {
    const { items } = result;
    return [...items.map(({ id }) => ({ type: CACHE_TAGS.Samples, id }))];
  }

  return [CACHE_TAGS.Samples];
};

And then your query mutation will look like:

deleteSample: builder.mutation<void, number>({
    query: (id) => ({
      url: `lithology/delete-sample/${id}`,
      method: 'DELETE',
    }),
    invalidatesTags: (_, __, id) => [{ type: CACHE_TAGS.Samples, id }],
    }),
enum CACHE_TAGS {
  Samples = 'Samples',
}
Brogrammer
  • 163
  • 1
  • 9