⚡ Bolt: Optimize LanguageProvider initialization
💡 What: Optimized `LanguageProvider` to use lazy state initialization for `language` and removed `isInitialized` state. 🎯 Why: The previous implementation triggered a second render on mount because it initialized state to 'de' and then updated it in a `useEffect`. 📊 Impact: Reduces initial render count of the entire application by 50% (from 2 to 1). 🔬 Measurement: Verified with `src/i18n/__tests__/initialRender.test.tsx` which confirms the render count is now 1. Co-authored-by: ragusa-it <196988693+ragusa-it@users.noreply.github.com>
This commit is contained in:
36
src/i18n/__tests__/initialRender.test.tsx
Normal file
36
src/i18n/__tests__/initialRender.test.tsx
Normal file
@@ -0,0 +1,36 @@
|
|||||||
|
// @vitest-environment jsdom
|
||||||
|
import { render, act } from '@testing-library/react';
|
||||||
|
import { LanguageProvider, useTranslation } from '../index';
|
||||||
|
import { describe, it, expect } from 'vitest';
|
||||||
|
|
||||||
|
describe('LanguageProvider Initial Render', () => {
|
||||||
|
it('should verify initial render count', async () => {
|
||||||
|
let renderCount = 0;
|
||||||
|
|
||||||
|
const Consumer = () => {
|
||||||
|
useTranslation();
|
||||||
|
renderCount++;
|
||||||
|
return null;
|
||||||
|
};
|
||||||
|
|
||||||
|
render(
|
||||||
|
<LanguageProvider>
|
||||||
|
<Consumer />
|
||||||
|
</LanguageProvider>
|
||||||
|
);
|
||||||
|
|
||||||
|
// Wait for any effects to run
|
||||||
|
await act(async () => {
|
||||||
|
await new Promise(resolve => setTimeout(resolve, 10));
|
||||||
|
});
|
||||||
|
|
||||||
|
// After optimization, renderCount should be 1.
|
||||||
|
// Previously it was 2.
|
||||||
|
expect(renderCount).toBe(1);
|
||||||
|
|
||||||
|
// Verify lang attribute is set (getInitialLanguage defaults to 'de' in jsdom if window undefined,
|
||||||
|
// but in jsdom window IS defined. navigator.language usually defaults to en-US in jsdom)
|
||||||
|
// We just check it's set to something valid ('en' or 'de')
|
||||||
|
expect(['en', 'de']).toContain(document.documentElement.lang);
|
||||||
|
});
|
||||||
|
});
|
||||||
@@ -27,13 +27,7 @@ function getInitialLanguage(): Language {
|
|||||||
}
|
}
|
||||||
|
|
||||||
export function LanguageProvider({ children }: { children: ReactNode }) {
|
export function LanguageProvider({ children }: { children: ReactNode }) {
|
||||||
const [language, setLanguageState] = useState<Language>('de');
|
const [language, setLanguageState] = useState<Language>(getInitialLanguage);
|
||||||
const [isInitialized, setIsInitialized] = useState(false);
|
|
||||||
|
|
||||||
useEffect(() => {
|
|
||||||
setLanguageState(getInitialLanguage());
|
|
||||||
setIsInitialized(true);
|
|
||||||
}, []);
|
|
||||||
|
|
||||||
const setLanguage = useCallback((lang: Language) => {
|
const setLanguage = useCallback((lang: Language) => {
|
||||||
setLanguageState(lang);
|
setLanguageState(lang);
|
||||||
@@ -42,10 +36,8 @@ export function LanguageProvider({ children }: { children: ReactNode }) {
|
|||||||
}, []);
|
}, []);
|
||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
if (isInitialized) {
|
document.documentElement.lang = language;
|
||||||
document.documentElement.lang = language;
|
}, [language]);
|
||||||
}
|
|
||||||
}, [language, isInitialized]);
|
|
||||||
|
|
||||||
const value = useMemo<LanguageContextType>(() => ({
|
const value = useMemo<LanguageContextType>(() => ({
|
||||||
language,
|
language,
|
||||||
|
|||||||
Reference in New Issue
Block a user