reactjs - การกำหนดค่าอ้างอิงขององค์ประกอบใหม่ตามสถานะ
ฉันมีอาร์เรย์ที่กำลังวนลูปเพื่อสร้างองค์ประกอบ div และขึ้นอยู่กับว่า div ใดเป็น ‘active’ (ได้มาจาก state) ฉันต้องการให้มันมี property ref ref นี้ยังเป็นพารามิเตอร์สำหรับ hook ที่ฉันใช้เพื่อเพิ่มตัวฟัง onclick ให้กับ ref นั้น สิ่งนี้ทำงานได้ดีเมื่อ div แรกเป็น active แต่เมื่อ state ของฉันเปลี่ยนไปทำให้ div ที่สองเป็น active ตัวฟัง onclick จะไม่ถูกเปิดใช้งานบน div ที่สอง มีไอเดียไหมว่าฉันจะแก้ปัญหานี้ได้อย่างไร
ไฟล์ส่วนประกอบ:
const [active, setActive] = useState(0);
const ref = useRef<HTMLDivElement>(null);
const { element } = useClick(ref);
return (
<div style={{ position: 'relative' }}>
{cards.map((card, index) => (
<div
{...(index === active ? { ref } : { 'aria-hidden': 'true' })}
>
<Card>
<div className={styles.title}>{card}</div>
</Card>
</div>
))}
</div>
);
ฮุคที่กำหนดเอง:
const useClick = (
element: RefObject<HTMLElement>
): {
element: RefObject<HTMLElement>;
} => {
const onClick = (): void => {
console.log('clicked');
};
useEffect(() => {
if (!element.current) {
return undefined;
}
element.current.addEventListener('click', onClick);
return (): void => {
element.current?.removeEventListener('click', onClick);
};
}, [element]);
return { element };
};
export default useClick;
ฉันคาดว่าตัวจัดการ onclick จะถูกลบออกจากองค์ประกอบแรกเมื่อมันไม่ทำงานแล้ว และถูกย้ายไปยัง div ที่ 2 ในลูป ฉันลองใช้วิธีการกับการใช้ array ของ refs เพื่อให้แต่ละ div มี ref ของตัวเองแต่ไม่ได้ผลเมื่อลองใช้ index ของ ref เป็นพารามิเตอร์ของ custom hook ของฉัน ฉันสามารถเห็นว่า state ของฉันกำลังเปลี่ยนแปลง (active) อย่างถูกต้อง แต่ฉันได้แก้ไขโค้ดนั้นเพราะมันยาวและซับซ้อนมากมีข้อมูล IP และดูเหมือนไม่เกี่ยวข้องกับปัญหา
คำตอบ #1
ถ้าสิ่งเดียวที่คุณสนใจคือ onClick ให้ใช้มันโดยตรงโดยไม่ต้องใช้ ref และไม่ต้องตั้งค่าเองใน useEffect:
<div
{...(index === active
? { onClick }
: { 'aria-hidden': 'true' })
}
>
ทำไมมันถึงใช้ไม่ได้?
ตัว ref ที่คุณกำลังใช้นั้นเป็นการอ้างอิงวัตถุ ซึ่งมีคุณสมบัติ current (ref={ current }) ในขณะที่ current เปลี่ยนแปลงตาม div ที่มันถูกใช้ ref จะยังคงเหมือนเดิม และ useEffect จะไม่ถูกเรียกใช้งาน
เปลี่ยน dependencies ให้ดูที่ element.current และเพิ่ม onClick ด้วย เพราะมันก็เป็น dependency ของ useEffect ด้วยเช่นกัน:
useEffect(() => {
if (!element.current) {
return undefined;
}
element.current.addEventListener('click', onClick);
return (): void => {
element.current?.removeEventListener('click', onClick);
};
}, [element.current, onClick]);
อีกตัวเลือกหนึ่งคือการใช้ฟังก์ชัน ref ร่วมกับ useState:
const [active, setActive] = useState(0);
const [ref, setRef] = useState(null); // the state is used as ref
const { element } = useClick(ref);
<div
// use setRef as a function ref
{...(index === active ? { ref: setRef } : { 'aria-hidden': 'true' })}
>
// in your custom hook
useEffect(() => {
// in this case element doesn't have current
if (!element) return undefined;
element?.addEventListener('click', onClick);
return (): void => {
element?.removeEventListener('click', onClick);
};
}, [element]);
