0

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;
Ali Bidjandy
  • 361
  • 6
  • 15
  • It seems that in your code you are synchronically dispatching actions from within your component code, at least in https://github.com/alibidjandy/burger/blob/main/src/components/Layouts/Index.tsx . Please note that in React, that is never allowed. React might rerender that component 500 times and it would lead to your dispatch 500 times - it might even lead to endless loops. Always only dispatch in event handlers or useEffect. As you seem to rely on rerender to trigger some side effects that might very well be the source of your problem. – phry Dec 25 '21 at 08:23
  • hi , hope you see my comment again . I fixed some of the previous wrong way of fetch actions but the main problem still have been remaining . if you check the Burger app , you'll figure out the first request doesn't saved on database (after refresh the page) so you need to push the buttons every time want to send a request twice to get the result . I used http patch to update any branch of my database , but I don't think so this is relative to PATCH – Ali Bidjandy Dec 28 '21 at 20:43
  • Well, you are definitely sending that PATCH and it comes back with an older state so I would search for the error on the API side, not on the react/redux/RTK Query side. I have no experience how that works with firebase exactly though, sorry. Maybe re-ask the question more centered around the firebase side? – phry Dec 28 '21 at 20:52
  • ok thank you so much – Ali Bidjandy Dec 28 '21 at 20:55
  • Hi , I've done my project this time with MongoDb (mongoose) again got the same problem as I got in working with firebase . if you want I could deploy my project somewhere like Netlify again otherwise If you could rely on my words as 4 years experienced in programming there's something big problem in RTK query in working with databases and it doesn't matter which one . – Ali Bidjandy Jan 02 '22 at 12:59
  • Since nobody except you seems to have those problems I would rather assume that you are using it wrong in some way. But unless you can create a small reproduction of your problem, not a full app that someone has to dig in and understand, it might be difficult for anyone to help you. And to be clear: I mean something with 3 or 4 components max, not 50 files in 10 folders. – phry Jan 02 '22 at 13:44

1 Answers1

1

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.

phry
  • 35,762
  • 5
  • 67
  • 81
  • thank you so much please just do me another favor after push a button to increase or decrease the amount of every one of those foods , got the new modified value from server 4 or 5 time it's like I got the expected data 4 or 5 time even after got unchanged data first for 3 time get the currect modified data at last I've been trying to manage side-effects with useEffect() but couldn't succeed – Ali Bidjandy Jan 06 '22 at 12:22