Fix refetch happening when switching budget files

This commit is contained in:
Joel Jeremy Marquez
2026-02-23 23:26:25 +00:00
parent 7995d659ab
commit 6fa4d673cf
4 changed files with 35 additions and 13 deletions

View File

@@ -1,5 +1,6 @@
import { createSlice } from '@reduxjs/toolkit';
import type { PayloadAction } from '@reduxjs/toolkit';
import { type QueryClient } from '@tanstack/react-query';
import { t } from 'i18next';
import { send } from 'loot-core/platform/client/connection';
@@ -98,16 +99,34 @@ export const loadBudget = createAppAsyncThunk(
},
);
function invalidateClosedBudgetQueries(queryClient: QueryClient) {
// Invalidate all queries but do not cause a refetch.
// This is because we want to clear out all the budget data from the queries,
// but we don't want to trigger a bunch of error states from the queries trying
// to fetch data for a budget that is now closed. The next time a budget is loaded,
// the queries will refetch with the correct budget id.
queryClient.invalidateQueries({
refetchType: 'none',
});
// Invalidate the metadata query since the budget is now closed.
// We want to cause a refetch so that the app can update to show the correct state
// (e.g. show the manager page if no budget is open).
queryClient.invalidateQueries({
queryKey: prefQueries.listMetadata().queryKey,
});
}
export const closeBudget = createAppAsyncThunk(
`${sliceName}/closeBudget`,
async (_, { dispatch, extra: { queryClient } }) => {
const prefs = await queryClient.ensureQueryData(prefQueries.listMetadata());
if (prefs && prefs.id) {
dispatch(resetApp());
queryClient.clear();
dispatch(setAppState({ loadingText: t('Closing...') }));
await send('close-budget');
dispatch(setAppState({ loadingText: null }));
invalidateClosedBudgetQueries(queryClient);
if (localStorage.getItem('SharedArrayBufferOverride')) {
window.location.reload();
}
@@ -121,7 +140,7 @@ export const closeBudgetUI = createAppAsyncThunk(
const prefs = await queryClient.ensureQueryData(prefQueries.listMetadata());
if (prefs && prefs.id) {
dispatch(resetApp());
queryClient.clear();
invalidateClosedBudgetQueries(queryClient);
}
},
);

View File

@@ -92,9 +92,7 @@ function AppInner() {
loadingText: t('Loading global preferences...'),
}),
);
void queryClient.invalidateQueries({
queryKey: prefQueries.listGlobal().queryKey,
});
void queryClient.prefetchQuery(prefQueries.listGlobal());
// Open the last opened budget, if any
dispatch(

View File

@@ -192,9 +192,6 @@ export function FinancesApp() {
const scrollableRef = useRef<HTMLDivElement>(null);
// Prefetch preferences
usePrefetchQuery(prefQueries.list());
return (
<View style={{ height: '100%' }}>
<RouterBehaviors />

View File

@@ -12,7 +12,7 @@ import type {
import { setI18NextLanguage } from '@desktop-client/i18n';
export type AllPrefs = {
local: MetadataPrefs;
metadata: MetadataPrefs;
global: GlobalPrefs;
synced: SyncedPrefs;
server: ServerPrefs;
@@ -25,7 +25,7 @@ export const prefQueries = {
queryOptions<AllPrefs>({
queryKey: [...prefQueries.lists(), 'all'],
queryFn: async ({ client }) => {
const [localPrefs, globalPrefs, syncedPrefs] = await Promise.all([
const [metadataPrefs, globalPrefs, syncedPrefs] = await Promise.all([
client.ensureQueryData(prefQueries.listMetadata()),
client.ensureQueryData(prefQueries.listGlobal()),
client.ensureQueryData(prefQueries.listSynced()),
@@ -43,14 +43,14 @@ export const prefQueries = {
setI18NextLanguage(globalPrefs.language ?? '');
return {
local: localPrefs,
metadata: metadataPrefs,
global: globalPrefs,
synced: syncedPrefs,
server: {}, // Server prefs are loaded separately
};
},
placeholderData: {
local: {},
metadata: {},
global: {},
synced: {},
server: {},
@@ -81,7 +81,15 @@ export const prefQueries = {
listSynced: () =>
queryOptions<SyncedPrefs>({
queryKey: [...prefQueries.lists(), 'synced'],
queryFn: async () => {
queryFn: async ({ client }) => {
const metadataPrefs = await client.getQueryData(
prefQueries.listMetadata().queryKey,
);
// Synced prefs are budget-specific, so if we don't have
// a budget loaded, just return an empty object.
if (!metadataPrefs?.id) {
return {};
}
return await send('preferences/get');
},
placeholderData: {},