Просмотр исходного кода

Neo: small render and request cleanups (#5826)

- useLayoutSettings: read the device language for `auto` once instead of on
  every render of each consumer (Intl / RNLocalize lookup). Not cached in SSR.
- Native tabs layout: drop the effect that called i18n.changeLanguage after
  hydrate() / setLang() had already switched it. A second change to the same
  language still re-rendered every useTranslation consumer.
- fetcher: copy the caller's headers instead of mutating the object.
- proxy: drop the leftover x-hello-from-middleware1 debug header.

Co-authored-by: Claude Opus 5.5 <noreply@anthropic.com>
RomanL 1 неделя назад
Родитель
Сommit
98360b79c4

+ 5 - 9
neo/apps/expo/app/(tabs)/_layout.js

@@ -21,7 +21,7 @@ if (!i18n.isInitialized) {
     i18n.use(initReactI18next).init({
         compatibilityJSON: 'v3',
         resources: resources,
-        lng: 'en', // initial language, updated in useEffect
+        lng: 'en', // initial language, switched by useLayoutSettings hydrate()
         fallbackLng: 'en',
         interpolation: {
             escapeValue: false
@@ -41,7 +41,10 @@ const AppLayout = React.memo(() => {
         RNScreenshotPrevent.enableSecureView();
     }*/
 
-    const { langCode, themeName } = useLayoutSettings();
+    // Also loads the stored settings; their hydrate() and setLang() switch the
+    // i18n language, so no effect here (a second changeLanguage to the same
+    // language still re-renders every useTranslation consumer).
+    const { themeName } = useLayoutSettings();
 
 
     useEffect(() => {
@@ -61,13 +64,6 @@ const AppLayout = React.memo(() => {
         });*/
     }, []);
 
-    useEffect(() => {
-        // i18n is already initialized synchronously — just update language
-        if (i18n.isInitialized && langCode) {
-            i18n.changeLanguage(langCode);
-        }
-    }, [langCode]);
-
     useEffect(() => {
         Uniwind.setTheme(themeName !== 'auto' ? themeName : 'system');
     }, [themeName]);

+ 0 - 1
neo/apps/next/proxy.js

@@ -83,7 +83,6 @@ function rewriteToUna(request, tenant, unaPath) {
     }
 
     const tmpHeaders = new Headers(request.headers);
-    tmpHeaders.set('x-hello-from-middleware1', 'hello');
     tmpHeaders.set('authorization', `Bearer ${unaApiKey}`);
     tmpHeaders.set('cookie', cookieHeaderFromRequest(request));
 

+ 13 - 1
neo/packages/app/context/layout-settings.ts

@@ -63,7 +63,19 @@ const getDefaultLangCode = (): string => {
     }
 };
 
-const resolveLangCode = (value: string | undefined): string => value && value != 'auto' ? value : getDefaultLangCode();
+/**
+ * Device language for `auto`, read once: every `useLayoutSettings` consumer
+ * resolves it on each render, and the locale lookup (Intl / RNLocalize) is not
+ * free. Not cached during SSR, where there is no device.
+ */
+let deviceLangCode: string | null = null;
+const getDeviceLangCode = (): string => {
+    if (Platform.OS === 'web' && typeof window === 'undefined') return getDefaultLangCode();
+    if (deviceLangCode === null) deviceLangCode = getDefaultLangCode();
+    return deviceLangCode;
+};
+
+const resolveLangCode = (value: string | undefined): string => value && value != 'auto' ? value : getDeviceLangCode();
 
 const getCookieValue = (name: string): string => {
     if (Platform.OS !== 'web' || typeof document === 'undefined') return '';

+ 2 - 4
neo/packages/app/lib/fetcher.ts

@@ -145,10 +145,8 @@ export async function fetcherRaw(host: string, mixed: FetcherRequest, fetchOptio
     else {
         path = mixed;
     }
-    if (undefined === headers)
-        headers = {};
-
-    
+    // A copy: the caller's object may be reused for other requests.
+    headers = { ...headers };
 
     // add token and origin headers when necessary
     if (token)