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

السؤال

نشر

مرحبا لدي مكون أب يحتوي على منطق بسيط ويحتوي أيضا على مكون ابن ومشكلتي هي أنه عندما يعاد تشغيل المكون الاب يعاد تشغيل المكون الابن أيضا رغم أنه لم يتغير شئ في المكون الابن 

603de0ff74cee_Peek2021-03-0207-53.gif.55264b393ecbdb0bcf5765b09d35d75e.gif

المكون الاب

import { useState, useEffect } from 'react';
import Child from './Child';

export default function ParentComponent() {
  const [lang, setLang] = useState('');
  const [framework, setFramwoek] = useState('');
  const whichFamousFramwork = () => {
    switch (lang) {
      case 'javascript':
        return setFramwoek('react');
      case 'python':
        return setFramwoek('django');
      case 'php':
        return setFramwoek('laravel');
      default:
        // eslint-disable-next-line no-unused-expressions
        'django';
    }
  };
  useEffect(() => {
    let mounted = true;
    if (mounted) {
      whichFamousFramwork();
    }
    return () => (mounted = false);
  }, [lang]);

  return (
    <div dir="rtl">
      <h1>اختر لغة وسنخبرك بأفضل فرايموورك</h1>
      <div>
        <button onClick={() => setLang('javascript')}>{'javascript'}</button>
        <button onClick={() => setLang('python')}>{'python'}</button>
        <button onClick={() => setLang('php')}>{'php'}</button>
      </div>
      {lang && (
        <p>
          بالنسبة ل <span>{framework}</span>, {lang} هو أفضل فرايموورك
        </p>
      )}
      <Child />
    </div>
  );
}

المكون الابن

import { useRef } from 'react';
function Child() {
  const renderCount = useRef(0);
  return (
    <div>
      <p>
        لم يتغير شئ داخل child لكن اعيد تشغيله <span>{renderCount.current++} مرة</span>
      </p>
    </div>
  );
}
export default Child;

هل من طريقة لمعالجة الامر?

Recommended Posts

  • 0
نشر

يمكنك استخدام react.memo في child لحل هذه المشكلة

react.memo ستحرص أن المكون لن يعاد تشغيله ان لم يتغير فيه شئ

import React, { useRef } from 'react';
function Child() {
  const renderCount = useRef(0);
  return (
    <div>
      <p>
        لم يتغير شئ داخل child لكن اعيد تشغيله <span>{renderCount.current++} مرة</span>
      </p>
    </div>
  );
}
export default React.memo(Child);

603de2b9cdd0b_Peek2021-03-0208-00.gif.83932036a2857d6e35922ce82414c5db.gif

  • 0
نشر

هنالك عدة أخطاء في كودك، اﻷولى أن هذا الكود:

useEffect(() => {
  let mounted = true;
  if (mounted) {
    whichFamousFramwork();
  }
  return () => (mounted = false);
}, [lang]);

مكافئ تماماً لهذا الكود:

useEffect(() => {
    whichFamousFramwork();
}, [lang]);

الثانية أن الـuseEffect وكذلك هذا السطر:

const [framework, setFramwoek] = useState('');

لا داعي لهما، يمكن استبدال Parent بهذا الكود:

export default function ParentComponent() {
  const [lang, setLang] = useState('');
  let framework;
  switch (lang) {
    case 'javascript':
      framework = 'react';
    case 'python':
      framework = 'django';
    case 'php':
      framework = 'laravel';
    default:
      // eslint-disable-next-line no-unused-expressions
      framework = 'django';
  }


  return (
    <div dir="rtl">
      <h1>اختر لغة وسنخبرك بأفضل فرايموورك</h1>
      <div>
        <button onClick={() => setLang('javascript')}>javascript</button>
        <button onClick={() => setLang('python')}>python</button>
        <button onClick={() => setLang('php')}>php</button>
      </div>
      {lang && (
        <p>
          بالنسبة ل <span>{framework}</span>, {lang} هو أفضل فرايموورك
        </p>
      )}
      <Child />
    </div>
  );
}

بالنسبة للـChild فإعادة تشغيله عند إعادة تشغيل المكون اﻷب أمر طبيعي ولا يجب تجنبه إلا إذا سبب ذلك مشاكل في performance حينها نلجأ ﻷمثال react.memo. إن كان إعادة تشغيل اﻻبن تسبب خطأً في logic فالمشكلة في اﻻبن وليس في اﻷب، في حالتك بالتحديد المشكلة في استخدام ref بهذه الطريقة ﻷنك تزيده مع كل استدعاء لتابع اﻻبن فمن الطبيعي أن يتغير اﻻبن عند عمل rerender له.

المفضل في حالتك استعمال useState إما في اﻷب وتمرر للابن كـprops أو في اﻻبن وحينها يجب أن يكون هناك زر ما لتغيير state بدلاً من تغييره في جسم render حتى لا تتسبب في حلقة لا نهائية.

بشكل عام لا يجوز تغيير state أو ref داخل render مباشرةً وإنما في حدث مثل onClick أو غيره ﻷن تغييره في render مباشرةً دائماً يسبب مشاكل مثل مشكلتك.

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

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

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

×   لقد أضفت محتوى بخط أو تنسيق مختلف.   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.

  • إعلانات

  • تابعنا على



×
×
  • أضف...