Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

polling polls one additional time after unsubscribe #1691

Closed
dapperdandev opened this issue Nov 4, 2021 · 14 comments
Closed

polling polls one additional time after unsubscribe #1691

dapperdandev opened this issue Nov 4, 2021 · 14 comments
Labels
bug Something isn't working

Comments

@dapperdandev
Copy link

dapperdandev commented Nov 4, 2021

Full Disclosure: I'm using ngrx-rtk-query with Angular. It might be their problem.

Environment

  • @reduxjs/toolkit: 1.6.2
  • ngrx-rtk-query: 2.3.0
  • node: 14.16.1
  • npm: 6.14.2
  • OS: Windows 10
  • Browser: Edge (Chromium)

Summary
I have an endpoint that takes paging params, e.g., {pageNumber: number, pageSize: number}. I refetch the data every 30 seconds to ensure the latest data is visible to the user.

rtk-query will send the last request of any query that didn't send prior to the arg change.

For example, if a user is on page 1, then goes to page 2, the following requests will be sent in this order:

/api/reservedwords?pageNumber=1&pageSize=10
/api/reservedwords?pageNumber=2&pageSize=10
/api/reservedwords?pageNumber=1&pageSize=10 // should not be sent
/api/reservedwords?pageNumber=2&pageSize=10

Here's the relevant code

// reserved-words.api.ts
export const api = createApi({
    baseQuery: fetchBaseQuery({ baseUrl: '/api' }),
    endpoints: (build) => ({
        getReservedWords: build.query<PagedResource<ReservedWordResource>, ReservedWordsQueryParams | void>({
            query: (params: ReservedWordsQueryParams) => ({
                url: 'reservedwords',
                params
            }),
            providesTags: [cacheTags.reservedWords]
        })
    })
});

export const { useGetReservedWordsQuery } = api;

// reserved-words-api.facade.ts
...
@Injectable({
    providedIn: 'root'
})
export class ReservedWordsApiFacade {
    public getReservedWords$(params: Observable<ReservedWordsQueryParams>): ReturnType<typeof useGetReservedWordsQuery> {
        return useGetReservedWordsQuery(params, { pollingInterval: 30000 });
    }
}

// reserved-words.component.ts
...
export class ReservedWordsComponent
    public query$ = new BehaviorSubject<ReservedWordsQueryParams>({ pageNumber: 1, pageSize: 10 });
    ...

    constructor(private reservedWordsApi: ReservedWordsApiFacade) {}

    public ngOnInit(): void {
        const sub = this.reservedWordsApi
            .getReservedWords$(this.query$)
            .pipe(tap((x) => console.log('from component', x.originalArgs)))  // Works fine here. Only logs when expected
            .subscribe((res) => {
                // do stuff with res
            });

        this.subscriptions.push(sub);
    }
...

---

Update: Remove Facade Code to make more readable.
@dapperdandev dapperdandev changed the title pollingInterval Should Have Option Cancel Unfulfilled Requests On Argument Change pollingInterval Should Have Option Cancel to Cancel Unfulfilled Requests On Argument Change Nov 4, 2021
@markerikson
Copy link
Collaborator

Hmm. To check, what you're saying is that you clicked and changed an argument, and then the previous poll went out? not that the arg change happened while the poll request was in flight? Just want to distinguish between "canceling a pending timer" and "canceling an in-flight HTTP request", which are completely different things.

@dapperdandev
Copy link
Author

@markerikson

Hmm. To check, what you're saying is that you clicked and changed an argument, and then the previous poll went out?

That's correct.

Also like you said, it seems like it doesn't cancel the pending timer.

To add a tad more info:
The facade and component don't have any problems. The problem doesn't exist until inside of the endpoint:

getAll: build.query<PagedResource<ReservedWordResource>, ReservedWordsQueryParams | void>({
    query: (params: ReservedWordsQueryParams) => {
        console.log('params: ', params); // logs the query that shouldn't be sent
        return {
            url: '',
            params: { ...baseParams, ...params }
        };
    },
    providesTags: [cacheTags.reservedWords]
}),

@markerikson
Copy link
Collaborator

Yeah, all the timing behavior is done in the middleware.

I suspect there's just no "cancel existing timer on arg change" logic in there.

@dapperdandev
Copy link
Author

dapperdandev commented Nov 5, 2021

Is that something I should be adding, or should rtk do that out of the box?

Updating my original example. Same issue without the facade, so cleaning it up a bit.

@markerikson
Copy link
Collaborator

Lenz would know more, but this sounds like a bug to me - just a use case that wasn't considered and handled.

@phryneas
Copy link
Member

phryneas commented Nov 5, 2021

It sounds like a bug.

We already had a report of this before if I remember correctly, but the author didn't come around to provide a reproduction yet.

I'll add it to the list - but it might take some time.

@phryneas phryneas added the bug Something isn't working label Nov 5, 2021
@phryneas phryneas changed the title pollingInterval Should Have Option Cancel to Cancel Unfulfilled Requests On Argument Change polling polls one additional time after unsubscribe Nov 5, 2021
@dapperdandev
Copy link
Author

Thanks @phryneas . Do you need me to create a small project with a repro? I wouldn't be familiar with React enough to use rtk-query out of the box, but I could put something together with code very similar to what I have above.

@GadiRiversideFM
Copy link

@phryneas is there an update on this issue? I experience the same issue with React 17.0.2 and @reduxjs/toolkit: 1.6.2

@phryneas
Copy link
Member

phryneas commented Jan 3, 2022

No, this is still open. PRs are welcome, but I have too much going on in real life to get to this at the moment, sorry.

@GadiRiversideFM
Copy link

@phryneas any workaround?

@phryneas
Copy link
Member

phryneas commented Jan 3, 2022

I would have said so if I knew about one. As I said, PRs are welcome.

@dapperdandev
Copy link
Author

@phryneas PR submitted.

If I understand correctly, state.subscriptions was keeps old subscriptions by queryCacheKey, but sets them to {}:

Here's a screenshot from putting a watch on it in vscode with npm link.

image

At this point, the args have been updated to request pageNumber: 2, so subscriptions["getAll({'pageNumber': 1, pageSize: 10})"] should no longer be polling.

I'll continue the conversation related to my PR in the PR comments.

@dapperdandev
Copy link
Author

Fixed by #1933. Thank you so much @msutkowski !!

@saadkhan8573
Copy link

saadkhan8573 commented May 17, 2022

` import { createApi, fetchBaseQuery } from "@reduxjs/toolkit/query/react";
import { Products } from "../models/products.model";

export const productsApi = createApi({
reducerPath: "productsApi",
tagTypes: ["Products"],
baseQuery: fetchBaseQuery({
baseUrl: process.env.NEXT_PUBLIC_BASE_URL,
}),
endpoints: (builder) => ({
products: builder.query<Products[], any>({
query: ({ brand, color, selectedCategory, name, basePrice, finalPrice }) => {
console.log("Saad",brand, color, selectedCategory, name, basePrice, finalPrice)
return {
url: "/product/filter",
params: { brand, color, selectedCategory, name, basePrice, finalPrice },
};
},
providesTags: ["Products"],
}),
newArrivals: builder.query<Products[], void>({
query: () => "/product/newarrival",
providesTags: ["Products"],
}),
popularProducts: builder.query<Products[], void>({
query: () => "/product",
providesTags: ["Products"],
}),
}),
});

export const {
useProductsQuery,
usePopularProductsQuery,
useNewArrivalsQuery,
} = productsApi; `

const { data, isLoading, isSuccess, isError } = useProductsQuery({ brand: selectedBrands[0], color: selectedColor, selectedCategory, basePrice: price[0], finalPrice: price[1], });

const { productView, selectedCategory, selectedBrands, selectedColor, ratingCount, isRating, price, isPrice } = useSelector((state: RootStateOrAny) => state.productSidebar);

image

its not working for me
when i select the category Joggers so its work fine, then i select the heels so its also work fine and when i again click on joggers so its doesnt work second time
whats can b issue?

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
bug Something isn't working
Projects
None yet
Development

Successfully merging a pull request may close this issue.

5 participants