Search code examples
reactjsredux-toolkitrtk-query

the first request doesn't send to the database in working with RTK query


In my project I'd like to increase and decrease amount of the foods listed . but after push the "More" button in the first request doesn't change anything in database but after push it again in second request just increse it once (after this refresh the page you'll figure it out). actually I don't know why the first request doesn't counted .

Demo :https://laughing-jang-201dc1.netlify.app/ .

Github : https://github.com/alibidjandy/burger

this is the main RTK Query configuration :

https://github.com/alibidjandy/burger/blob/main/src/Api/apiSlice.ts

import { current } from "@reduxjs/toolkit";
import { createApi, fetchBaseQuery } from "@reduxjs/toolkit/query/react";
import {
  AllBurgerType,
  BurgerType,
  IngredientsType,
} from "../components/Layouts/burger/burgerSlice/burgerSlice";

export const burgerApi = createApi({
  reducerPath: "burgerApi",
  tagTypes: ["Ingredients"],
  baseQuery: fetchBaseQuery({
    baseUrl:
      "https://burger-order-brown-default-rtdb.europe-west1.firebasedatabase.app",
  }),
  endpoints: (builder) => ({
    getIngredients: builder.query<BurgerType, undefined>({
      // query: () => `/.json`,
      query: () => {
        return { url: "/.json", method: "GET" };
      },
      providesTags: ["Ingredients"],
    }),
    editIngredients: builder.mutation({
      query: (initialIngredients) => {
        return { url: "/.json", method: "PATCH", body: initialIngredients };
      },
      invalidatesTags: ["Ingredients"],
    }),
    increase: builder.mutation({
      query: ({ ing }) => {
        return {
          url: `/ingredients/${ing.id}/.json`,
          method: "PATCH",
          body: ing,
        };
      },
      async onQueryStarted({ ing }, { dispatch, queryFulfilled }) {
        const patchResult = dispatch(
          burgerApi.util.updateQueryData(
            "getIngredients",
            undefined,
            (draft) => {
              console.log("increase");
              // debugger;
              const ingredient = draft.ingredients.find(
                (ingredient) => ingredient.title === ing.title
              );
              if (ingredient) {
                console.log(current(ingredient));
                ingredient.Qty!++;
              }
            }
          )
        );
        try {
          await queryFulfilled;
        } catch {
          console.log("crashed");
          patchResult.undo();
        }
      },
    }),
    decrease: builder.mutation({
      query: ({ ing, indexIng }) => {
        return {
          url: `/ingredients/${indexIng}/.json`,
          method: "POST",
          body: ing,
        };
      },
      async onQueryStarted({ ing, indexIng }, { dispatch, queryFulfilled }) {
        const patchResult = dispatch(
          burgerApi.util.updateQueryData(
            "getIngredients",
            undefined,
            (draft) => {
              console.log("decrese");
              const ingredient = draft.ingredients[indexIng];
              if (ingredient.Qty !== undefined && ingredient.Qty > 0) {
                draft.totalCost = +(draft.totalCost -=
                  ingredient.cost!).toFixed(2);
                ingredient.Qty--;
              }
            }
          )
        );
        try {
          await queryFulfilled;
        } catch {
          patchResult.undo();
        }
      },
    }),
  }),
});
export const { editIngredients, getIngredients } = burgerApi.endpoints;
export const {
  useGetIngredientsQuery,
  useEditIngredientsMutation,
  useIncreaseMutation,
  useDecreaseMutation,
} = burgerApi;

Solution

  • Wait... I'm just re-reading your code. I think you might have a very wrong idea on what onQueryStarted and updateQueryData do. onQueryStarted runs after your request has been sent to the server. updateQueryData only updates your data on the client. So you send the old client-side data to the server and then update it on the client side. Yes, no wonder your data is always one step behind. You need to send updated data to the server in the first place.

    You would need to do something like

        increase: builder.mutation({
          query: ({ ing }) => {
            return {
              url: `/ingredients/${ing.id}/.json`,
              method: "PATCH",
              body: { ...ing, Qty: ing.Qty + 1 }
            };
          },
    

    and no onQueryStarted at all. Just use invalidatesTags to have the correct data refetched from the server afterwards.

    Also, as I stumbled over that somewhere else in your code: you are generating an id using nanoid() and using that as key. Never do that. A key has to be stable, not be a different one on every render. That will always cause React to destroy the whole child DOM on every render and throw away the whole local state of all child components as well.