🌐 Detecting your location…
📢 Advertisement — Configure AdSense in Appearance → Customize → AdSense Settings

كيفية إصلاح خطأ React Hook useState الذي يُسمى خطأ مشروط

⏱️2 min read  ·  408 words

الخطأيتم استدعاء خطاف التفاعل “useState” بشكل مشروط. يجب استدعاء خطافات React بنفس الترتيب في كل تصيير مكون يعد أحد أكثر أخطاء React شيوعًا. إنه ينتهك قواعد الخطافات. وإليك سبب حدوث ذلك وكيفية إصلاح كل متغير.

لماذا توجد هذه القاعدة

React يتتبع الخطافات من خلالطلب الاتصال، وليس بالاسم. في كل تصيير، تتوقع React نفس الخطافات بنفس التسلسل. إذا كان الخطاف داخل شرط ما، فقد يتم تشغيله في تصيير واحد ولكن ليس في التصيير التالي – مما يؤدي إلى كسر التتبع الداخلي لـ React والتسبب في تعيين الحالة إلى الخطاف الخطأ.

الكود المكسور

// 🐛 Hook inside a condition — VIOLATES rules of hooks
function Profile({ userId }) {
  if (!userId) {
    return <div>No user</div>;  // early return BEFORE hooks
  }

  const [user, setUser] = useState(null);  // ❌ conditionally called
  // If userId is falsy, this hook is skipped — breaks React's tracking

  return <div>{user?.name}</div>;
}

الإصلاح 1: استدعاء الخطافات أولاً، والحالة لاحقًا

// ✅ All hooks at the top, unconditionally
function Profile({ userId }) {
  const [user, setUser] = useState(null);  // always called

  // Conditional logic AFTER all hooks
  if (!userId) {
    return <div>No user</div>;
  }

  return <div>{user?.name}</div>;
}

الإصلاح 2: ربط داخل كتلة الشرط

// 🐛 useEffect inside an if
function Component({ isActive }) {
  if (isActive) {
    useEffect(() => {          // ❌ conditional hook
      console.log('active');
    }, []);
  }
}

// ✅ Move the condition INSIDE the hook
function Component({ isActive }) {
  useEffect(() => {
    if (isActive) {            // condition inside the hook
      console.log('active');
    }
  }, [isActive]);
}

الإصلاح 3: ربط داخل حلقة

// 🐛 Hook in a loop — order changes if items.length changes
function List({ items }) {
  return items.map(item => {
    const [selected, setSelected] = useState(false);  // ❌ in a loop
    return <Item key={item.id} />;
  });
}

// ✅ Extract into a child component — each has its own hooks
function List({ items }) {
  return items.map(item => <Item key={item.id} item={item} />);
}

function Item({ item }) {
  const [selected, setSelected] = useState(false);  // ✅ top level of component
  return <div onClick={() => setSelected(!selected)}>{item.name}</div>;
}

الإصلاح 4: ربط بعد العودة المبكرة

// 🐛 Hook after a conditional return
function Widget({ data }) {
  const [count, setCount] = useState(0);

  if (!data) return null;      // early return

  const [name, setName] = useState('');  // ❌ never reached when !data

  return <div>{name}: {count}</div>;
}

// ✅ ALL hooks before ANY conditional return
function Widget({ data }) {
  const [count, setCount] = useState(0);
  const [name, setName] = useState('');  // moved up

  if (!data) return null;      // early return AFTER all hooks

  return <div>{name}: {count}</div>;
}

قاعدتا الخطافات

  1. استدعاء الخطافات فقط في المستوى الأعلى – لا تدخل أبدًا في الشروط أو الحلقات أو الوظائف المتداخلة. دائما بنفس الترتيب.
  2. استدعاء الخطافات فقط من وظائف React – مكونات التفاعل أو الخطافات المخصصة (الوظائف التي تبدأ بـuse). ليس من وظائف JavaScript العادية.

التعامل مع المنطق الشرطي بشكل صحيح

function Dashboard({ user, showStats }) {
  // ✅ Always call all hooks unconditionally
  const [data, setData] = useState(null);
  const [loading, setLoading] = useState(true);

  useEffect(() => {
    // Conditions go INSIDE the hook, not around it
    if (showStats) {
      fetchStats().then(setData).finally(() => setLoading(false));
    } else {
      setLoading(false);
    }
  }, [showStats]);

  // Conditional RENDERING is fine — it's not a conditional hook
  if (!user) return <Login />;
  if (loading) return <Spinner />;

  return showStats ? <Stats data={data} /> : <Overview />;
}

فرض القواعد باستخدام ESLint

npm install --save-dev eslint-plugin-react-hooks

// .eslintrc — catches these errors before runtime
{
  "plugins": ["react-hooks"],
  "rules": {
    "react-hooks/rules-of-hooks": "error",
    "react-hooks/exhaustive-deps": "warn"
  }
}

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

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

س: هل يمكنني استخدام الشروط داخل الخطاف؟
ج: نعم! الشروط الموجودة داخل الخطاف (داخل رد اتصال useEffect، على سبيل المثال) جيدة. تحظر القاعدة فقط استدعاء الخطاف نفسه بشكل مشروط.

س: كيف يمكنني تشغيل التأثير بشكل مشروط؟
ج: ضع الشرط داخل نص التأثير وقم بتضمين متغير الشرط في مصفوفة التبعية:useEffect(() => { if (cond) {...} }, [cond]).

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

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

الخلاصة

الخطأ “استدعاء خطاف التفاعل المشروط” يعني أن الخطاف موجود داخل شرط أو حلقة أو بعد إرجاع مبكر. الإصلاح هو نفسه دائمًا:قم باستدعاء جميع الخطافات دون قيد أو شرط في الجزء العلوي من المكون الخاص بك، قبل أي عوائد شرطية أو منطق. ضع الشروط داخل الخطافات (في جسم التأثير)، وليس حولها. تثبيتeslint-plugin-react-hooks لاكتشاف هذه الأخطاء تلقائيًا قبل أن تصل إلى وقت التشغيل – إنها أفضل وسيلة حماية ضد انتهاكات قاعدة الربط.

✍️ Leave a Comment

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

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