🌐 Detecting your location…

كيفية إصلاح خطأ فشل الترطيب في Next.js: الحل الكامل

⏱️3 min read  ·  491 words

الخطأفشل الترطيب لأن واجهة المستخدم الأولية لا تتطابق مع ما تم تقديمه على الخادم (أو “محتوى النص لا يتطابق مع HTML المقدم من الخادم”) في Next.js يعني أن HTML الذي يعرضه الخادم يختلف عما يعرضه React على العميل. إليك سبب حدوث ذلك وكيفية إصلاح كل الأسباب.

ما هو الترطيب

يعرض Next.js صفحتك بتنسيق HTML على الخادم (SSR)، ويرسلها إلى المتصفح للعرض الأولي السريع، ثم يقوم React “بترطيبها” — مع إرفاق التفاعل. يتطلب الترطيب أن يتطابق HTML المقدم من الخادم والعرض الأول للعميل تمامًا. إذا كانت مختلفة، فإن React ستتسبب في خطأ ترطيب لأنها لا تستطيع إصلاح عدم التطابق.

السبب 1: استخدام واجهات برمجة التطبيقات للمتصفح فقط أثناء العرض

// 🐛 window/localStorage don't exist on the server → mismatch
function Component() {
  const theme = localStorage.getItem('theme');   // ❌ undefined on server
  return <div className={theme}>...</div>;
}

// ✅ Access browser APIs only after mount (in useEffect)
function Component() {
  const [theme, setTheme] = useState(null);

  useEffect(() => {
    setTheme(localStorage.getItem('theme'));   // runs only on client
  }, []);

  return <div className={theme || 'default'}>...</div>;
}

السبب 2: التواريخ والأوقات

// 🐛 The server and client render at different times → mismatch
function Component() {
  return <div>{new Date().toLocaleString()}</div>;   // ❌ differs
}

// ✅ Render the date only on the client
function Component() {
  const [date, setDate] = useState(null);
  useEffect(() => { setDate(new Date().toLocaleString()); }, []);
  return <div>{date ?? 'Loading...'}</div>;
}

السبب 3: القيم العشوائية

// 🐛 Math.random() produces different values on server vs client
function Component() {
  const id = Math.random();   // ❌ different each render
  return <div id={id}>...</div>;
}

// ✅ Use React's useId for stable IDs, or generate in useEffect
import { useId } from 'react';
function Component() {
  const id = useId();   // stable across server and client
  return <div id={id}>...</div>;
}

السبب 4: تداخل HTML غير صالح

// 🐛 Invalid nesting gets "corrected" by the browser, causing mismatch
<p>
  <div>Content</div>   {/* ❌ div inside p is invalid */}
</p>
// The browser moves the div out, but React's tree still has it nested

// ✅ Use valid HTML nesting
<div>
  <div>Content</div>   {/* valid */}
</div>
// Common culprits: div/p inside p, block elements inside inline elements,
// invalid table structure

السبب 5: تعديل ملحقات المستعرض HTML

// Some browser extensions inject attributes/elements into your HTML
// before React hydrates, causing a mismatch (e.g., Grammarly, dark mode extensions)

// This often shows as a mismatch on the body or specific elements.
// You can suppress the warning on a specific element if needed:
<body suppressHydrationWarning>
  {/* Use sparingly - only when the mismatch is expected/harmless */}
</body>
// But first verify it's an extension, not a real bug in your code.

السبب 6: العرض الشرطي بناءً على حالة العميل

// 🐛 Rendering differently based on something only known on the client
function Component() {
  const isMobile = window.innerWidth < 768;   // ❌ window undefined on server
  return isMobile ? <Mobile /> : <Desktop />;
}

// ✅ Start with a consistent server render, adjust after mount
function Component() {
  const [isMobile, setIsMobile] = useState(false);   // consistent default

  useEffect(() => {
    setIsMobile(window.innerWidth < 768);
    const onResize = () => setIsMobile(window.innerWidth < 768);
    window.addEventListener('resize', onResize);
    return () => window.removeEventListener('resize', onResize);
  }, []);

  return isMobile ? <Mobile /> : <Desktop />;
}

نمط مكون العميل فقط

// For components that genuinely can't be server-rendered,
// use dynamic import with ssr: false
import dynamic from 'next/dynamic';

const ClientOnlyChart = dynamic(() => import('./Chart'), {
  ssr: false,   // skip server rendering entirely
  loading: () => <div>Loading chart...</div>,
});
// The component renders only on the client - no hydration mismatch possible

الأسئلة المتداولة

س: ما الذي يسبب أخطاء الترطيب في أغلب الأحيان؟
ج: استخدام واجهات برمجة التطبيقات للمتصفح فقط (نافذة، تخزين محلي) أثناء العرض، أو عرض التواريخ/الأوقات أو القيم العشوائية التي تختلف بين الخادم والعميل، وتداخل HTML غير الصالح. الخيط المشترك: يتم عرض شيء ما على الخادم بشكل مختلف عن العميل. انقل المنطق الخاص بالعميل إلى useEffect.

س: كيف يمكنني استخدام localStorage دون أخطاء في الترطيب؟
ج: لا تصل إليه أثناء العرض (إنه غير محدد على الخادم). اقرأها في useEffect (الذي يعمل فقط على العميل) وقم بتخزين القيمة في الحالة. قم بتقديم إعداد افتراضي ثابت في البداية، ثم قم بالتحديث بعد التثبيت. يؤدي هذا إلى الحفاظ على تطابق عرض الخادم والعميل.

س: حدث خطأ الترطيب الخاص بي بسبب امتداد المتصفح. ماذا أفعل؟
ج: تعمل الإضافات مثل Grammarly على حقن السمات قبل الترطيب. تحقق من أنه الامتداد (اختبره في وضع التصفح المتخفي مع تعطيل الامتدادات). إذا كان غير ضار، يمكنك إضافةsuppressHydrationWarning إلى العنصر المتأثر – ولكن استخدمه بشكل مقتصد وفقط لإجراء تعديلات خارجية مؤكدة وغير ضارة، وليس لإخفاء الأخطاء الحقيقية.

س: متى يجب علي استخدام الاستيراد الديناميكي مع ssr: false؟
ج: بالنسبة للمكونات التي لا يمكن أو لا ينبغي أن يتم عرضها بواسطة الخادم – تلك التي تعتمد بشكل كبير على واجهات برمجة التطبيقات للمتصفح، أو مكتبات عملاء الجهات الخارجية فقط، أو التي لا تستفيد من SSR. إنه يتخطى عرض الخادم بالكامل، مما يزيل عدم تطابق الترطيب لهذا المكون، على حساب عدم وجود فائدة SSR له.

س: لماذا يعمل في التطوير ولكن الخطأ يظهر في بعض الأحيان؟
ج: يمكن أن يكون عدم تطابق الترطيب متقطعًا عندما يعتمد على التوقيت (التواريخ)، أو العشوائية، أو العوامل الخارجية (الامتدادات). إنها أخطاء حقيقية حتى عندما تكون متقطعة. إعادة الإنتاج بشكل موثوق من خلال تحديد الاختلافات بين عرض الخادم والعميل – عادةً واجهات برمجة تطبيقات المتصفح أو الوقت أو القيم العشوائية.

الخلاصة

تعني أخطاء ترطيب Next.js أن HTML الذي يعرضه الخادم لا يتطابق مع العرض الأول للعميل. الأسباب متسقة:واجهات برمجة التطبيقات للمتصفح فقط (النافذة، التخزين المحلي) المستخدمة أثناء العرض، والتواريخ/الأوقات أو القيم العشوائية التي تختلف، وتداخل HTML غير الصالح، والعرض الشرطي الخاص بالعميل. نمط الإصلاح هو نفسه: انقل المنطق الخاص بالعميل إلىuseEffect (الذي يعمل فقط على العميل)، ويقدم إعدادًا افتراضيًا ثابتًا في البداية، ثم يتم التحديث بعد التثبيت. استخدمuseId للمعرفات الثابتة، وتداخل HTML الصالح، وdynamic(..., ssr: false) للمكونات الحقيقية للعميل فقط. بمجرد أن يعرض خادمك وعميلك إنتاج HTML مطابقًا، تنجح عملية الترطيب. النموذج العقلي الرئيسي: أي شيء يتم عرضه يجب أن يكون متطابقًا على الخادم والعميل بالنسبة للعرض الأولي – أي شيء خاص بالعميل ينتمي إلى useEffect.

MD Rafikul Islam

Written by

MD Rafikul Islam is a software developer and the editor of TechPulse. He writes about developer tooling, hardware, and the practical decisions that come up in day-to-day engineering work — which laptop to buy, which framework to commit to, why a build broke at 2am. He tests the tools he writes about and says plainly when something is not worth the money. Corrections and corrections requests are welcome at rony.yf25@gmail.com.

✍️ Leave a Comment

Your email address will not be published. Required fields are marked *

🌐 Read in:🇬🇧 English🇩🇪 Deutsch🇧🇷 Português🇸🇦 العربية🇮🇳 हिन्दी🇧🇩 বাংলা