اذهب إلى المحتوى
  • 0

معالجة مشكل hydration في مشروع nextjs

محمود سعداوي2

السؤال

السلام عليكم.

الكود التالي 

import {NextIntlClientProvider} from 'next-intl';
import {getLocale, getMessages} from 'next-intl/server';
import { AppProvider } from "@/context/AppContext";
import { Tajawal } from "next/font/google";

const ubuntu = Tajawal({
  subsets: ["arabic"],
  weight: ["300", "400", "500", "700"],
});

export default async function RootLayout({ children }) {
    const locale = await getLocale();
    const messages = await getMessages();
    const direction = locale === "ar" ? "rtl" : "ltr";
    return (
        <html lang={locale} dir={direction}>
            <body className={ubuntu.className}>
                <NextIntlClientProvider messages={messages}>
                    <AppProvider>
                        {children}
                    </AppProvider>
                </NextIntlClientProvider>
            </body>
        </html>
    );
}

تسبب في هذا الخطأ

Console Error

Hydration failed because the server rendered HTML didn't match the client. As a result this tree will be regenerated on the client. This can happen if a SSR-ed Client Component used

- A server/client branch `if (typeof window !== 'undefined')`.
- Variable input such as `Date.now()` or `Math.random()` which changes each time it's called.
- Date formatting in a user's locale which doesn't match the server.
- External changing data without sending a snapshot of it along with the HTML.
- Invalid HTML tag nesting.

It can also happen if the client has a browser extension installed which messes with the HTML before React loaded.

See more info here: https://nextjs.org/docs/messages/react-hydration-error


- lang="en"
- dir="ltr"
- className="__className_f09b3f"
Call Stack
Next.js

شكرا لكم

رابط هذا التعليق
شارك على الشبكات الإجتماعية

Recommended Posts

  • 0

الخطأ "Hydration failed" في Next.js يعني أن HTML المنشئ على جانب الخادم (SSR) لا يتطابق مع HTML الذي تم إنشاؤه على جانب العميل وهذا عادة ما يكون بسبب اختلاف في البيانات أو الحالة أما في حالتك فالمشكلة في استخدام ubuntu.className داخل RootLayout لأن ubuntu.className هي خاصية ديناميكية، أي أنها تحسب في كل مرة يعاد تجميع المكون (React component) وبما أن Next.js يقوم بتحميل صفحة React من الخادم (SSR) ثم يحييها على جانب العميل (Client-side hydration)، فالتغييرات الديناميكية على الخادم قد لا تتطابق مع العميل، وبالتالي يحدث الخطأ "Hydration failed" لذا يمكن حل المشكلة عن طريق تخزين قيمة ubuntu.className في متغير ثابت داخل RootLayout ثم استخدامه في body:

import {NextIntlClientProvider} from 'next-intl';
import {getLocale, getMessages} from 'next-intl/server';
import { AppProvider } from "@/context/AppContext";
import { Tajawal } from "next/font/google";

const ubuntu = Tajawal({ subsets: ["arabic"], weight: ["300", "400", "500", "700"] });

export default async function RootLayout({ children }) {
  const locale = await getLocale();
  const messages = await getMessages();
  const direction = locale === "ar" ? "rtl" : "ltr";

  const fontClassName = ubuntu.className;  

  return (
    <html lang={locale} dir={direction}>
      <body className={fontClassName}>
        <NextIntlClientProvider messages={messages}>
          <AppProvider>
            {children}
          </AppProvider>
        </NextIntlClientProvider>
      </body>
    </html>
  );
}

هنا نقوم بحساب ubuntu.className مرة واحدة على جانب الخادم ثم React يقوم بحفظ هذه القيمة في fontClassName بعدها نستخدم القيمة الثابتة fontClassName داخل className في body و رياكت سيستخدم هذه القيمة المخزنة على جانب الخادم.

رابط هذا التعليق
شارك على الشبكات الإجتماعية

  • 0
بتاريخ 9 دقائق مضت قال عبد الوهاب بومعراف:

الخطأ "Hydration failed" في Next.js يعني أن HTML المنشئ على جانب الخادم (SSR) لا يتطابق مع HTML الذي تم إنشاؤه على جانب العميل وهذا عادة ما يكون بسبب اختلاف في البيانات أو الحالة أما في حالتك فالمشكلة في استخدام ubuntu.className داخل RootLayout لأن ubuntu.className هي خاصية ديناميكية، أي أنها تحسب في كل مرة يعاد تجميع المكون (React component) وبما أن Next.js يقوم بتحميل صفحة React من الخادم (SSR) ثم يحييها على جانب العميل (Client-side hydration)، فالتغييرات الديناميكية على الخادم قد لا تتطابق مع العميل، وبالتالي يحدث الخطأ "Hydration failed" لذا يمكن حل المشكلة عن طريق تخزين قيمة ubuntu.className في متغير ثابت داخل RootLayout ثم استخدامه في body:

import {NextIntlClientProvider} from 'next-intl';
import {getLocale, getMessages} from 'next-intl/server';
import { AppProvider } from "@/context/AppContext";
import { Tajawal } from "next/font/google";

const ubuntu = Tajawal({ subsets: ["arabic"], weight: ["300", "400", "500", "700"] });

export default async function RootLayout({ children }) {
  const locale = await getLocale();
  const messages = await getMessages();
  const direction = locale === "ar" ? "rtl" : "ltr";

  const fontClassName = ubuntu.className;  

  return (
    <html lang={locale} dir={direction}>
      <body className={fontClassName}>
        <NextIntlClientProvider messages={messages}>
          <AppProvider>
            {children}
          </AppProvider>
        </NextIntlClientProvider>
      </body>
    </html>
  );
}

هنا نقوم بحساب ubuntu.className مرة واحدة على جانب الخادم ثم React يقوم بحفظ هذه القيمة في fontClassName بعدها نستخدم القيمة الثابتة fontClassName داخل className في body و رياكت سيستخدم هذه القيمة المخزنة على جانب الخادم.

لايزال نفس الخطأ وأرجح أن يكون بسبب lang أو dir.

رابط هذا التعليق
شارك على الشبكات الإجتماعية

  • 0
بتاريخ 48 دقائق مضت قال محمود سعداوي2:
- lang="en"
- dir="ltr"
- className="__className_f09b3f"

لاحظ أنه يخبرك أن الثلاث خصائص السابقة من المحتمل أنها هي التي تسبب المشكلة لأنها تتغير وتختلف عند جهة العميل عن الكود الذي تم تصيره في جهة الخادم.

وإذا قمت بالذهاب إلى الرابط الموجود في الرسالة ستجد أنه ينصحك بإستخدام useEffect لتجنب مشكلة إختلاف الأكواد بين جهة العميل وجهة الخادم .

يرجى تجربة الكود التالي وإخباري بالنتيجة :

import {NextIntlClientProvider} from 'next-intl';
import {getLocale, getMessages} from 'next-intl/server';
import { AppProvider } from "@/context/AppContext";
import { Tajawal } from "next/font/google";
import { useEffect, useState } from 'react';

const ubuntu = Tajawal({
  subsets: ["arabic"],
  weight: ["300", "400", "500", "700"],
});

export default async function RootLayout({ children }) {
    const [locale, setLocale] = useState("en");
    const [messages, setMessages] = useState(null);
    const [direction, setDirection] = useState("ltr");

    useEffect(() => {
        async function fetchData() {
            const currentLocale = await getLocale();
            const currentMessages = await getMessages();
            setLocale(currentLocale);
            setMessages(currentMessages);
            setDirection(currentLocale === "ar" ? "rtl" : "ltr");
        }
        fetchData();
    }, []);

    return (
        <html lang={locale} dir={direction}>
            <body className={ubuntu.className}>
                {messages && (
                    <NextIntlClientProvider messages={messages}>
                        <AppProvider>
                            {children}
                        </AppProvider>
                    </NextIntlClientProvider>
                )}
            </body>
        </html>
    );
}

لقد قمت بوضع locale و direction بداخل useEffect لتجنب حدوث مشكلة إختلاف الأكواد . إذا ظهرت نفس المشكلة يرجى حذف الكود الخاص className={ubuntu.className} والتجربة مرة أخرى وإذا تم حلها يمكنك وضع متغير جديد كما اقترح عليك المدرب عبدالوهاب بداخل useEffect . وإذا ظلت المشكلة موجودة قم بمحاولة إلغاء أكواد local و direction و classname وأنظر هل السبب هنا أم لا حيث من الممكن أن يكون المشكلة في مكون أخر مختلف.

رابط هذا التعليق
شارك على الشبكات الإجتماعية

  • 0
بتاريخ 52 دقائق مضت قال محمد عاطف17:

لاحظ أنه يخبرك أن الثلاث خصائص السابقة من المحتمل أنها هي التي تسبب المشكلة لأنها تتغير وتختلف عند جهة العميل عن الكود الذي تم تصيره في جهة الخادم.

وإذا قمت بالذهاب إلى الرابط الموجود في الرسالة ستجد أنه ينصحك بإستخدام useEffect لتجنب مشكلة إختلاف الأكواد بين جهة العميل وجهة الخادم .

يرجى تجربة الكود التالي وإخباري بالنتيجة :

import {NextIntlClientProvider} from 'next-intl';
import {getLocale, getMessages} from 'next-intl/server';
import { AppProvider } from "@/context/AppContext";
import { Tajawal } from "next/font/google";
import { useEffect, useState } from 'react';

const ubuntu = Tajawal({
  subsets: ["arabic"],
  weight: ["300", "400", "500", "700"],
});

export default async function RootLayout({ children }) {
    const [locale, setLocale] = useState("en");
    const [messages, setMessages] = useState(null);
    const [direction, setDirection] = useState("ltr");

    useEffect(() => {
        async function fetchData() {
            const currentLocale = await getLocale();
            const currentMessages = await getMessages();
            setLocale(currentLocale);
            setMessages(currentMessages);
            setDirection(currentLocale === "ar" ? "rtl" : "ltr");
        }
        fetchData();
    }, []);

    return (
        <html lang={locale} dir={direction}>
            <body className={ubuntu.className}>
                {messages && (
                    <NextIntlClientProvider messages={messages}>
                        <AppProvider>
                            {children}
                        </AppProvider>
                    </NextIntlClientProvider>
                )}
            </body>
        </html>
    );
}

لقد قمت بوضع locale و direction بداخل useEffect لتجنب حدوث مشكلة إختلاف الأكواد . إذا ظهرت نفس المشكلة يرجى حذف الكود الخاص className={ubuntu.className} والتجربة مرة أخرى وإذا تم حلها يمكنك وضع متغير جديد كما اقترح عليك المدرب عبدالوهاب بداخل useEffect . وإذا ظلت المشكلة موجودة قم بمحاولة إلغاء أكواد local و direction و classname وأنظر هل السبب هنا أم لا حيث من الممكن أن يكون المشكلة في مكون أخر مختلف.

شكرا ولكن ظهر هذا الخطأ

 node_modules\next-intl\dist\development\shared\NextIntlClientProvider.js (23:11) @ NextIntlClientProvider
 ⨯ Error: Failed to determine locale in `NextIntlClientProvider`, please provide the `locale` prop explicitly.

See https://next-intl-docs.vercel.app/docs/configuration#locale
    at AsyncResource.runInAsyncScope (node:async_hooks:206:9)
digest: "1085825041"
  21 |
  22 |   if (!locale) {
> 23 |     throw new Error('Failed to determine locale in `NextIntlClientProvider`, please provide the `locale` prop explicitly.\n\nSee https://next-intl-docs.vercel.app/docs/configuration#locale' );
     |           ^
  24 |   }
  25 |   return /*#__PURE__*/React__default.default.createElement(_IntlProvider.IntlProvider, _rollupPluginBabelHelpers.extends({
  26 |     locale: locale
 GET /en 500 in 4488ms

 

رابط هذا التعليق
شارك على الشبكات الإجتماعية

انضم إلى النقاش

يمكنك أن تنشر الآن وتسجل لاحقًا. إذا كان لديك حساب، فسجل الدخول الآن لتنشر باسم حسابك.

زائر
أجب على هذا السؤال...

×   لقد أضفت محتوى بخط أو تنسيق مختلف.   Restore formatting

  Only 75 emoji are allowed.

×   Your link has been automatically embedded.   Display as a link instead

×   جرى استعادة المحتوى السابق..   امسح المحرر

×   You cannot paste images directly. Upload or insert images from URL.

  • إعلانات

  • تابعنا على



×
×
  • أضف...