Optimize LanguageProvider context value memoization

Co-authored-by: ragusa-it <196988693+ragusa-it@users.noreply.github.com>
This commit is contained in:
google-labs-jules[bot]
2026-01-29 05:00:43 +00:00
parent 0ba794a1d3
commit 169cbc1bcb
2 changed files with 55 additions and 5 deletions

View File

@@ -0,0 +1,50 @@
// @vitest-environment jsdom
import React, { useState } from 'react';
import { render, screen, act } from '@testing-library/react';
import { LanguageProvider, useTranslation } from '../index';
import { describe, it, expect } from 'vitest';
describe('LanguageProvider Performance', () => {
it('should prevent consumers from re-rendering when provider re-renders but value is unchanged', async () => {
let renderCount = 0;
const Consumer = () => {
useTranslation();
renderCount++;
return <div data-testid="consumer">Consumer</div>;
};
const MemoizedConsumer = React.memo(Consumer);
const Wrapper = () => {
const [count, setCount] = useState(0);
return (
<div>
<button onClick={() => setCount(c => c + 1)}>Force Render</button>
<div data-testid="count">{count}</div>
<LanguageProvider>
<MemoizedConsumer />
</LanguageProvider>
</div>
);
};
render(<Wrapper />);
// Wait for effects to settle (language detection might trigger update)
await act(async () => {
await new Promise(resolve => setTimeout(resolve, 0));
});
const initialRenderCount = renderCount;
// Force re-render of Wrapper, which causes re-render of LanguageProvider
const button = screen.getByText('Force Render');
await act(async () => {
button.click();
});
// After optimization, renderCount should not increase.
expect(renderCount).toBe(initialRenderCount);
});
});

View File

@@ -1,4 +1,4 @@
import { createContext, useContext, useState, useEffect, type ReactNode } from 'react';
import { createContext, useContext, useState, useEffect, useMemo, useCallback, type ReactNode } from 'react';
import { de, type Translations } from './de';
import { en } from './en';
@@ -35,11 +35,11 @@ export function LanguageProvider({ children }: { children: ReactNode }) {
setIsInitialized(true);
}, []);
const setLanguage = (lang: Language) => {
const setLanguage = useCallback((lang: Language) => {
setLanguageState(lang);
localStorage.setItem(STORAGE_KEY, lang);
document.documentElement.lang = lang;
};
}, []);
useEffect(() => {
if (isInitialized) {
@@ -47,11 +47,11 @@ export function LanguageProvider({ children }: { children: ReactNode }) {
}
}, [language, isInitialized]);
const value: LanguageContextType = {
const value = useMemo<LanguageContextType>(() => ({
language,
setLanguage,
t: translations[language],
};
}), [language, setLanguage]);
return (
<LanguageContext.Provider value={value}>