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

السؤال

نشر

هل توجد طريقة لتشغيل كود معين (دالة ما) قبل إزالة العنصر من الصفحة DOM؟ بحيث يتم تنفيذ الكود وبعد الإنتهاء تمامًا يتم إزالة العنصر من الصفحة بالكامل.

ما أحاول القيام به هو عمل زر Toggle وعند الضغط عليه يظهر صندوق box وعند الضغط مرة أخرى على زر Toggle يجب حذف هذا الصندوق من الصفحة، ولكن أريد كذلك أن يتم تنفيذ كود معين قبل أن تتم إزالة العنصر من الصفحة، لذلك قمت بكتابة الكود التالي:

function App() {
  const [active, setActive] = useState(true);
  
  if(!active) return null;
  return <><button onClick={() => setActive(!active)}> Toggle </button> <Box /> </>;
}
function Box() {
  const boxRef = useRef();
  const callBeforeUnmount = () => {
    // use boxRef to do something
  }
  return <div className="box" ref={boxRef}>red box</div>
}

المشكلة هنا أن boxRef.current تصبح null عند تغير active إلى false ويتم إزالة العنصر بشكل مباشر.

كيف يمكنني تشغيل الدالة callBeforeUnmount عند الضغط على  وإنتظار إنتهائها وبعد ذلك إزالة العنصر من الصفحة؟

Recommended Posts

  • 1
نشر
import React, {useEffect, useState, useRef} from 'react';
function App() {
  const [active, setActive] = useState(true);
  

  return( 
        <>
            <button onClick={() => setActive(!active)}> Toggle </button> 
            <Box setActive={setActive} active={active} /> 
            {/*  مررنا قيمة active هنا حتى يتمكن الصندوق من تحسسها*/}
        </>
  )
}
function Box({active, setActive}) {
  // هنا اصبح لدينا وصول الى قيمة active
  const [displayMode, setDisplayMode]= useState("HIDE") // نضيف هذه الدالة للتحكم بحالة الزر محلياً داخل الحاوية
  const boxRef = useRef();
  const callBeforeUnmount = () => {
    // use boxRef to do something
    if(boxRef && boxRef.current){
      boxRef.current.style.color="red" // هنا قم بالتعديل مثلا على لون الزر
      setTimeout(()=>{
        setDisplayMode("HIDE") 
      }, 500 ) // ثم قم بإخفاءه
 // ثم قم بإخفاءه
    } // لا يتضح لي بالضبط ما تحاول فعله في هذه الدالة لكن هذا مجرد مثال
    console.log("callBeforeUnmount!!!") 
  }
  
  useEffect(()=> { 
    if(!active){ // نستدعي الدالة فقط عندما يكون الصندوق  نشط
        callBeforeUnmount()
    } else {
      setDisplayMode("SHOW") // اذا كان الأمر هو نشط نقوم بأظهار الزر بتغيير قيمة الهوك مسبق التعريف
    }
  }, [active])  // نضبط الهوك ليستدعي الدالة المطلوبة عندما تتغير قيمة active

  if(displayMode==="HIDE") return null; // نقلنا هذا الكود الى هنا ليقوم بأخفاء الصندوق فقط بدل اخفاء كل شيء
  return <div className="box" ref={boxRef}>red box</div>
}

export default App;

تستطيع ذلك من خلال إستعمالك ل useEffect مع إجراء بعض التعديلات على الكود الخاص بك. لاحظ التعليقات التي وضعتها لك في أماكن التعديل. التغييرات التي أجريناها على كل من المكونين تضمن لنا التحكم بحالة الصندوق محلياً داخل المكون box وكذلك حل مشكلة إخفاء الزر في المكون app  مع الصندوق .

  • 1
نشر

لحل هذه المشكلة يمكنك فعل الآتي:

- بداية قم بنقل boxRef إلى الApp

function App() {
      const [active, setActive] = useState(true);
      const boxRef = useRef(null);
		...
		...
}

ومرّره إلى ال Box ك props:

function App() {
      ...
	  ...

      return (
            <>
                  <button onClick={handleToggle}> Toggle </button>{" "}
                  <Box boxRef={boxRef} />{" "}
            </>
      );
}

وعدّل على Box واجعله كالآتي:

function Box({ boxRef }) {
      return (
            <div className="box" ref={boxRef}>
                  red box
            </div>
      );
}

هكذا نكون قد حافظنا على مرجع العنصر box ضمن المكون App فيمكننا استخدامه قبل أن نقوم بتغيير قيمة الactive. كل ما عليك الآن إنشاء الطريقة handleToggle:

const handleToggle = () => {
            // use boxRef to do something
            console.log(boxRef.current);
            setActive(!active);
      };

واستخدامها في الbutton :

<button onClick={handleToggle}> Toggle </button>

 

لاحظت أنك تحذف الbutton مع الbox عند الضغط على toggle للمرة الثانية، إذا كنت تريد الحفاظ على الbutton وحذف الbox فقط يجب عليك عوضا عن إرجاع الnull في حال الactive قيمته false أرجع الbutton:

if (!active) return <button onClick={handleToggle}> Toggle </button>;

 

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

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

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

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

  • إعلانات

  • تابعنا على



×
×
  • أضف...