Skip to content

Commit 2c2cc52

Browse files
committed
fix: rare useEffect cycle with multiple tabs
1 parent e1e6f7b commit 2c2cc52

File tree

2 files changed

+93
-5
lines changed

2 files changed

+93
-5
lines changed

apps/meteor/client/providers/UserProvider/UserProvider.tsx

Lines changed: 32 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -157,16 +157,43 @@ const UserProvider = ({ children }: UserProviderProps): ReactElement => {
157157
);
158158

159159
useEffect(() => {
160-
if (!!userId && preferedLanguage !== userLanguage) {
161-
setUserPreferences({ data: { language: preferedLanguage } });
162-
setUserLanguage(preferedLanguage);
160+
if (user?.language === undefined) {
161+
return;
163162
}
164163

165-
if (user?.language !== undefined && user.language !== userLanguage) {
164+
if (user.language !== userLanguage) {
166165
setUserLanguage(user.language);
166+
}
167+
168+
if (user.language !== preferedLanguage && preferedLanguage === userLanguage) {
167169
setPreferedLanguage(user.language);
170+
return;
171+
}
172+
173+
if (user.language === userLanguage && preferedLanguage !== userLanguage) {
174+
setPreferedLanguage(userLanguage);
175+
}
176+
}, [preferedLanguage, setPreferedLanguage, setUserLanguage, user?.language, userLanguage]);
177+
178+
useEffect(() => {
179+
if (!userId || user?.language === undefined) {
180+
return;
168181
}
169-
}, [preferedLanguage, setPreferedLanguage, setUserLanguage, user?.language, userLanguage, userId, setUserPreferences]);
182+
183+
if (user.language !== userLanguage) {
184+
return;
185+
}
186+
187+
if (preferedLanguage !== userLanguage) {
188+
return;
189+
}
190+
191+
if (preferedLanguage === user.language) {
192+
return;
193+
}
194+
195+
void setUserPreferences({ data: { language: preferedLanguage } });
196+
}, [preferedLanguage, setUserPreferences, user?.language, userId, userLanguage]);
170197

171198
useEffect(() => {
172199
if (!samlCredentialToken && !inviteTokenHash) {
Lines changed: 61 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,61 @@
1+
import { Users } from './fixtures/userStates';
2+
import { expect, test } from './utils/test';
3+
4+
const DEFAULT_LANGUAGE = 'en';
5+
const DIVERGING_LANGUAGE = 'pt-BR';
6+
const USERS_SET_PREFERENCES_ENDPOINT = '/api/v1/users.setPreferences';
7+
8+
test.use({ storageState: Users.user1.state });
9+
10+
test.describe('user-language-preferences', () => {
11+
test.beforeAll(async ({ api }) => {
12+
const response = await api.post('/users.setPreferences', {
13+
userId: Users.user1.data._id,
14+
data: { language: DEFAULT_LANGUAGE },
15+
});
16+
17+
expect(response.status()).toBe(200);
18+
});
19+
20+
test.afterAll(async ({ api }) => {
21+
const response = await api.post('/users.setPreferences', {
22+
userId: Users.user1.data._id,
23+
data: { language: DEFAULT_LANGUAGE },
24+
});
25+
26+
expect(response.status()).toBe(200);
27+
});
28+
29+
test('avoids redundant language preference updates when cache diverges', async ({ page }) => {
30+
await page.addInitScript(([language, serverLanguage]) => {
31+
// Emulate a stale tab whose cache disagrees with the server preference.
32+
window.localStorage.setItem('fuselage-localStorage-userLanguage', JSON.stringify(language));
33+
window.localStorage.setItem('fuselage-localStorage-preferedLanguage', JSON.stringify(serverLanguage));
34+
}, [DIVERGING_LANGUAGE, DEFAULT_LANGUAGE]);
35+
36+
const languageRequests: string[] = [];
37+
38+
page.on('request', (request) => {
39+
if (request.method() !== 'POST' || !request.url().includes(USERS_SET_PREFERENCES_ENDPOINT)) {
40+
return;
41+
}
42+
43+
try {
44+
const payload = JSON.parse(request.postData() ?? '{}');
45+
const language = payload?.data?.language;
46+
47+
if (language) {
48+
languageRequests.push(language);
49+
}
50+
} catch {
51+
// Ignore malformed payloads produced outside this scenario.
52+
}
53+
});
54+
55+
await page.goto('/home');
56+
57+
await page.waitForTimeout(3000);
58+
59+
expect(languageRequests).toHaveLength(0);
60+
});
61+
});

0 commit comments

Comments
 (0)