Skip to content

RTKQ tag invalidation not working in a complex Next app #4769

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

Closed
markerikson opened this issue Dec 14, 2024 · 7 comments
Closed

RTKQ tag invalidation not working in a complex Next app #4769

markerikson opened this issue Dec 14, 2024 · 7 comments

Comments

@markerikson
Copy link
Collaborator

markerikson commented Dec 14, 2024

Honestly, in my experience tag invalidations do not seem to work as well as I believe one should expect them to work after splitting your API code; I followed this documentation here: https://redux-toolkit.js.org/rtk-query/usage/code-splitting to split the API in my Next.js 14 app into multiple files because I'm building a multi-tenant app where each subdomain app's API is contained within a subfolder in the root API folder—all of the endpoints of my API work as expected, except for tag invalidations.

My expectation was that because I was injecting all of my endpoints into an empty root API file, as depicted by the code splitting documentation guide, I should have been able to invalidate certain query endpoints after a mutation, even if that mutation came from the endpoints of another file because they're part of the same API. for example, in my root API folder, I have two subfolders, /admin and /finance, the admin subfolder contains all of the API endpoints for the admin subdomain app that have already been injected into the empty root API file where a single createApi instance is being called, and the same goes for the finance subfolder. so, I have one API with multiple endpoints being injected from multiple separate files, as instructed by the guide. now, what I want to happen is, when a user in the finance subdomain app sends a message or submits a service request from their dashboard to the admin app, I want to invalidate certain query endpoints in the /admin API file, so I can automatically trigger a refetch to keep my cache data up to date, but that does not seem to work; even though I'm invalidating the tags from the /finance API endpoints, the /admin API endpoints do not respond. The only time tag invalidation works is when the invalidation occurs from endpoints that exist in the same file. I made sure to define all of my "tagTypes" in the empty root API file thinking that would make them available to all the other endpoints that would later be injected, but that does not seem to be the case. only endpoints that exist in the same files can invalidate each other's tags, but that is not what I need.

further research has led me to look into streaming updates to see if that could be a potential solution, but all of my research keeps pointing me toward having to implement a solution like Websocket.io, but that would require me to set up a separate server, and I don't want to go in that direction. I want to keep everything within the next.js framework if possible. so, my question is, is there a way to invalidate tags across various subdomain apps and their respective injected API files? I want the various apps that will exist in my multi-tenant app to be able to not only communicate with each other but also trigger events in one another, like tag invalidation for starters. if this feature already exists, then can someone please help me understand what I'm doing wrong and how to fix it? if this feature does not exist, will you please add it to the future releases of RTKQ?

Originally posted by @Elieserlaguerre in #3692

@markerikson
Copy link
Collaborator Author

@Elieserlaguerre I've created this new issue based on your comment. Could you reply here with a link to either your real app Github repo, or a smaller example repo that shows this problem happening?

@Elieserlaguerre
Copy link

Elieserlaguerre commented Dec 14, 2024

@Elieserlaguerre I've created this new issue based on your comment. Could you reply here with a link to either your real app Github repo, or a smaller example repo that shows this problem happening?

I don't know how to share a link to my repo yet, but I did do some research on that and I found this: "fine-grained personal access tokens". it should give you temporary read-only access to my real app Github repo.

if this is not what you're looking for then perhaps this then? https://github.com/Elieserlaguerre/synergistic-enterprises

Empty root API file

import { createApi, fetchBaseQuery } from "@reduxjs/toolkit/query/react";

// initialize an empty api service that we'll inject endpoints into later as needed
export const multiTenantApi = createApi({
	reducerPath: "multiTenantApi",
	baseQuery: fetchBaseQuery({ baseUrl: "/api" }),
	endpoints: () => ({}),
	tagTypes: ["user", "album", "mail", "session", "helpCenter", "agreements", "documents", "financialStatement", "income", "credit", "events", "pendingEvent", "private money loan", "loan tracker", "loan summary", "message summary", "event summary", "document summary", "report summary", "login", "subdomain", "parent company", "company search", "employee search", "partner search", "vendor search", "client form search", "company form search", "administration", "admin message"]
});

API endpoints for /finance subfolder

import { multiTenantApi } from "./multiTenantApi";

export const financeApi = multiTenantApi.injectEndpoints({
	overrideExisting: false,
	endpoints: (build) => ({		
		guestMessage: build.mutation({
			query: (payload) => ({
				url: "/finance/contact-us/email/",
				method: "POST",
				body: payload
			}),			
			transformErrorResponse: (results) => results?.data?.message,
			invalidatesTags: [{ type: "mail" }, { type: "administration" }]
		}),
		createAppointments: build.mutation({
			query: (formData) => ({
				url: "/finance/contact-us/appointment",
				method: "POST",
				body: formData
			}),
			transformErrorResponse: (results) => results?.data?.message,
			invalidatesTags: [{ type: "appointment" }, { type: "administration" }]
		}),	

		// more endpoints...
	})
});

export const { 
	// many hooks ...
 } = financeApi;

API endpoints for /admin subfolder

import { multiTenantApi } from "./multiTenantApi";

export const adminApi = multiTenantApi.injectEndpoints({
	overrideExisting: false,
	endpoints: (build) => ({		
		getAdministration: build.query({
			query: () => ({
				url: "/admin/companies/administration",
				method: "GET"
			}),
			providesTags: [{ type: "administration" }],
			transformErrorResponse: (results) => results.data.message
		}),
		// more endpoints...
	})
});

export const { 
	// many hooks...
 } = adminApi;

Redux Store Configuration file

"use client";
import { configureStore } from "@reduxjs/toolkit";
import { setupListeners } from "@reduxjs/toolkit/query/react";
import userSlice from "../reducers/userSlice";
import storage from "redux-persist/lib/storage";
import { persistStore, persistReducer, FLUSH, REHYDRATE, PAUSE, PERSIST, PURGE, REGISTER } from "redux-persist";
import viewMailSlice from "../reducers/viewMailSlice";
import privateMoneyLoanProgress from "../reducers/privateMoneyLoanProgress";
import businessLoanProgress from "../reducers/businessLoanProgress";
import { multiTenantApi } from "../data-fetching/multiTenantApi";


const persistedUserReducer = persistReducer({ key: "current-user", storage }, userSlice);
const persistedPrivateMoneyStatus = persistReducer({ key: "private-money-application-pregress", storage }, privateMoneyLoanProgress);
const persistedBusinessLoanStatus = persistReducer({ key: "business-loan-application-progress", storage }, businessLoanProgress);
const persistMessageSlice = persistReducer({ key: "view-message", storage }, viewMailSlice);
const store = configureStore({
	reducer: {
		user: persistedUserReducer,
		privateMoneyProgress: persistedPrivateMoneyStatus,
		businessLoanProgress: persistedBusinessLoanStatus,
		viewMail: persistMessageSlice,
		[multiTenantApi.reducerPath]: multiTenantApi.reducer
	},
	middleware: (getDefaultMiddleware) =>
		getDefaultMiddleware({
			serializableCheck: {
				ignoreActions: [FLUSH, REHYDRATE, PAUSE, PERSIST, PURGE, REGISTER]
			}
		}).concat(multiTenantApi.middleware) //RTK Query setup
});

export const persistor = persistStore(store);

setupListeners(store.dispatch); //RTK Querry

export default store;

@markerikson
Copy link
Collaborator Author

markerikson commented Dec 14, 2024

@Elieserlaguerre yeah, the repo URL ( https://github.com/Elieserlaguerre/synergistic-enterprises ) is what I was asking for.

That said: Please don't paste Github access tokens in a public place! Anyone could use them!

@Elieserlaguerre
Copy link

okay, thanks for letting me, this was my first time trying to share a link so I wasn't sure how to go about it.

@markerikson
Copy link
Collaborator Author

It does look like that repo is private. The best way you can give me access is:

  • Go to the "Settings" tab for your repo
  • Go to "Collaborators and teams"
  • Click "Add people"
  • Look up my username ( markerikson )
  • Invite me with "Read" access

@Elieserlaguerre
Copy link

Elieserlaguerre commented Dec 14, 2024

I've sent you the invitation.

@markerikson
Copy link
Collaborator Author

Discussed externally - ultimately it's an architectural issue.

@markerikson markerikson closed this as not planned Won't fix, can't repro, duplicate, stale Dec 14, 2024
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

2 participants