ไทย

คู่มือฉบับสมบูรณ์เกี่ยวกับ React Portals ครอบคลุมกรณีการใช้งาน การนำไปใช้ ประโยชน์ และแนวทางปฏิบัติที่ดีที่สุดสำหรับการเรนเดอร์เนื้อหานอกลำดับชั้นคอมโพเนนต์มาตรฐาน

React Portals: การเรนเดอร์เนื้อหานอก Component Tree

React portals เป็นกลไกที่ทรงพลังสำหรับการเรนเดอร์ child components ไปยัง DOM node ที่อยู่นอกลำดับชั้น DOM ของ parent component เทคนิคนี้มีประโยชน์อย่างยิ่งในสถานการณ์ต่างๆ เช่น modals, tooltips และสถานการณ์ที่คุณต้องการควบคุมการจัดตำแหน่งและลำดับการซ้อนทับขององค์ประกอบบนหน้าเว็บอย่างแม่นยำ

React Portals คืออะไร?

ในแอปพลิเคชัน React ทั่วไป คอมโพเนนต์จะถูกเรนเดอร์ภายใต้โครงสร้างลำดับชั้นที่เข้มงวด parent component จะประกอบด้วย child components และต่อไปเรื่อยๆ อย่างไรก็ตาม บางครั้งคุณจำเป็นต้องหลุดออกจากโครงสร้างนี้ นี่คือจุดที่ React portals เข้ามามีบทบาท portal ช่วยให้คุณสามารถเรนเดอร์เนื้อหาของคอมโพเนนต์ไปยังส่วนอื่นของ DOM ได้ แม้ว่าส่วนนั้นจะไม่ได้เป็นส่วนที่สืบทอดโดยตรงจากคอมโพเนนต์ใน React tree ก็ตาม

ลองนึกภาพว่าคุณมีคอมโพเนนต์ modal ที่ต้องแสดงผลที่ระดับบนสุดของแอปพลิเคชันของคุณ โดยไม่คำนึงว่าจะถูกเรนเดอร์ที่ใดใน component tree หากไม่มี portals คุณอาจพยายามทำสิ่งนี้โดยใช้การกำหนดตำแหน่งแบบ absolute และ z-index ซึ่งอาจนำไปสู่ปัญหาการจัดสไตล์ที่ซับซ้อนและความขัดแย้งที่อาจเกิดขึ้นได้ แต่ด้วย portals คุณสามารถเรนเดอร์เนื้อหาของ modal ไปยัง DOM node ที่ระบุได้โดยตรง เช่น element "modal-root" ที่สร้างขึ้นโดยเฉพาะ เพื่อให้แน่ใจว่าจะถูกเรนเดอร์ในระดับที่ถูกต้องเสมอ

ทำไมต้องใช้ React Portals?

React Portals ช่วยแก้ปัญหาท้าทายที่พบบ่อยหลายประการในการพัฒนาเว็บ:

วิธีการนำ React Portals ไปใช้งาน

การใช้ React Portals นั้นตรงไปตรงมา นี่คือคำแนะนำทีละขั้นตอน:

  1. สร้าง DOM Node: ขั้นแรก สร้าง DOM node ที่คุณต้องการเรนเดอร์เนื้อหาของ portal โดยทั่วไปจะทำในไฟล์ `index.html` ของคุณ ตัวอย่างเช่น:
    <div id="modal-root"></div>
  2. ใช้ `ReactDOM.createPortal()`: ในคอมโพเนนต์ React ของคุณ ใช้เมธอด `ReactDOM.createPortal()` เพื่อเรนเดอร์เนื้อหาลงใน DOM node ที่สร้างขึ้น เมธอดนี้รับอาร์กิวเมนต์สองตัว: React node (เนื้อหาที่คุณต้องการเรนเดอร์) และ DOM node ที่คุณต้องการเรนเดอร์
    import ReactDOM from 'react-dom';
    
    function MyComponent() {
      return ReactDOM.createPortal(
        <div>This content is rendered in the modal-root!</div>,
        document.getElementById('modal-root')
      );
    }
    
    export default MyComponent;
  3. เรนเดอร์คอมโพเนนต์: เรนเดอร์คอมโพเนนต์ที่มี portal เหมือนกับที่คุณเรนเดอร์คอมโพเนนต์ React อื่นๆ
    function App() {
      return (
        <div>
          <h1>My App</h1>
          <MyComponent />
        </div>
      );
    }
    
    export default App;

ในตัวอย่างนี้ เนื้อหาภายใน `MyComponent` จะถูกเรนเดอร์เข้าไปใน element `modal-root` ถึงแม้ว่า `MyComponent` จะถูกเรนเดอร์อยู่ภายในคอมโพเนนต์ `App` ก็ตาม

ตัวอย่าง: การสร้างคอมโพเนนต์ Modal ด้วย React Portals

เรามาสร้างคอมโพเนนต์ modal ที่สมบูรณ์โดยใช้ React Portals ตัวอย่างนี้รวมถึงการจัดสไตล์พื้นฐานและฟังก์ชันการทำงานเพื่อเปิดและปิด modal

import React, { useState } from 'react';
import ReactDOM from 'react-dom';

const modalRoot = document.getElementById('modal-root');

function Modal({ children, onClose }) {
  const [isOpen, setIsOpen] = useState(true);

  const handleClose = () => {
    setIsOpen(false);
    onClose();
  };

  if (!isOpen) return null;

  return ReactDOM.createPortal(
    <div className="modal-overlay">
      <div className="modal">
        <div className="modal-content">
          {children}
        </div>
        <button onClick={handleClose}>Close</button>
      </div>
    </div>,
    modalRoot
  );
}

function App() {
  const [showModal, setShowModal] = useState(false);

  const handleOpenModal = () => {
    setShowModal(true);
  };

  const handleCloseModal = () => {
    setShowModal(false);
  };

  return (
    <div>
      <h1>My App</h1>
      <button onClick={handleOpenModal}>Open Modal</button>
      {showModal && (
        <Modal onClose={handleCloseModal}>
          <h2>Modal Content</h2>
          <p>This is the content of the modal.</p>
        </Modal>
      )}
    </div>
  );
}

export default App;

ในตัวอย่างนี้:

คุณยังต้องเพิ่มสไตล์ CSS บางอย่างให้กับคลาส `modal-overlay` และ `modal` เพื่อจัดตำแหน่ง modal บนหน้าจอให้ถูกต้อง ตัวอย่างเช่น:

.modal-overlay {
  position: fixed;
  top: 0;
  left: 0;
  width: 100%;
  height: 100%;
  background-color: rgba(0, 0, 0, 0.5);
  display: flex;
  justify-content: center;
  align-items: center;
  z-index: 1000;
}

.modal {
  background-color: white;
  padding: 20px;
  border-radius: 5px;
}

.modal-content {
  margin-bottom: 10px;
}

การจัดการ Events ด้วย Portals

ข้อควรพิจารณาที่สำคัญอย่างหนึ่งเมื่อใช้ portals คือวิธีการจัดการ event การเกิด event bubbling จะทำงานแตกต่างกับ portals เมื่อเทียบกับคอมโพเนนต์ React มาตรฐาน

เมื่อมี event เกิดขึ้นภายใน portal มันจะ bubble up ผ่าน DOM tree ตามปกติ อย่างไรก็ตาม ระบบ event ของ React จะปฏิบัติต่อ portal เหมือนเป็น React node ทั่วไป ซึ่งหมายความว่า event จะ bubble up ผ่าน React component tree ที่มี portal อยู่ด้วย

บางครั้งสิ่งนี้อาจนำไปสู่พฤติกรรมที่ไม่คาดคิดหากคุณไม่ระมัดระวัง ตัวอย่างเช่น หากคุณมี event handler บน parent component ที่ควรจะถูกทริกเกอร์โดย event ภายในคอมโพเนนต์นั้นเท่านั้น มันอาจถูกทริกเกอร์โดย event ภายใน portal ด้วย

เพื่อหลีกเลี่ยงปัญหาเหล่านี้ คุณสามารถใช้เมธอด `stopPropagation()` บน event object เพื่อป้องกันไม่ให้ event bubble up ต่อไป หรือคุณสามารถใช้ synthetic events ของ React และการเรนเดอร์ตามเงื่อนไขเพื่อควบคุมว่า event handler จะถูกทริกเกอร์เมื่อใด

นี่คือตัวอย่างของการใช้ `stopPropagation()` เพื่อป้องกันไม่ให้ event bubble up ไปยัง parent component:

function MyComponent() {
  const handleClick = (event) => {
    event.stopPropagation();
    console.log('Clicked inside the portal!');
  };

  return ReactDOM.createPortal(
    <div onClick={handleClick}>This content is rendered in the portal.</div>,
    document.getElementById('portal-root')
  );
}

ในตัวอย่างนี้ การคลิกที่เนื้อหาภายใน portal จะทริกเกอร์ฟังก์ชัน `handleClick` แต่ event จะไม่ bubble up ไปยัง parent components ใดๆ

แนวทางปฏิบัติที่ดีที่สุดสำหรับการใช้ React Portals

นี่คือแนวทางปฏิบัติที่ดีที่สุดที่ควรคำนึงถึงเมื่อทำงานกับ React Portals:

ทางเลือกอื่นนอกเหนือจาก React Portals

แม้ว่า React Portals จะเป็นเครื่องมือที่ทรงพลัง แต่ก็มีแนวทางอื่นที่คุณสามารถใช้เพื่อให้ได้ผลลัพธ์ที่คล้ายกัน ทางเลือกที่พบบ่อยบางอย่างได้แก่:

การเลือกใช้แนวทางใดขึ้นอยู่กับข้อกำหนดเฉพาะของแอปพลิเคชันของคุณและความซับซ้อนขององค์ประกอบ UI ที่คุณพยายามสร้าง โดยทั่วไปแล้ว Portals เป็นตัวเลือกที่ดีที่สุดเมื่อคุณต้องการควบคุมการจัดตำแหน่งและลำดับการซ้อนทับขององค์ประกอบอย่างแม่นยำ และต้องการหลีกเลี่ยง CSS conflicts

ข้อควรพิจารณาในระดับสากล (Global Considerations)

เมื่อพัฒนาแอปพลิเคชันสำหรับผู้ชมทั่วโลก สิ่งสำคัญคือต้องพิจารณาปัจจัยต่างๆ เช่น การแปลภาษา (localization), การเข้าถึง (accessibility) และความแตกต่างทางวัฒนธรรม React Portals สามารถมีบทบาทในการจัดการกับข้อควรพิจารณาเหล่านี้ได้:

โดยการคำนึงถึงข้อควรพิจารณาในระดับสากลเหล่านี้ คุณสามารถสร้างแอปพลิเคชันที่ครอบคลุมและเป็นมิตรต่อผู้ใช้มากขึ้นสำหรับผู้ชมที่หลากหลาย

บทสรุป

React Portals เป็นเครื่องมือที่ทรงพลังและหลากหลายสำหรับการเรนเดอร์เนื้อหานอก component tree มาตรฐาน มันเป็นโซลูชันที่สะอาดและสวยงามสำหรับรูปแบบ UI ทั่วไป เช่น modals, tooltips และ popovers การทำความเข้าใจวิธีการทำงานของ portals และการปฏิบัติตามแนวทางปฏิบัติที่ดีที่สุดจะช่วยให้คุณสร้างแอปพลิเคชัน React ที่ยืดหยุ่น บำรุงรักษาง่าย และเข้าถึงได้มากขึ้น

ลองทดลองใช้ portals ในโปรเจกต์ของคุณเองและค้นพบหลากหลายวิธีที่มันสามารถทำให้เวิร์กโฟลว์การพัฒนา UI ของคุณง่ายขึ้น อย่าลืมพิจารณาถึงการจัดการ event, การเข้าถึง และข้อควรพิจารณาในระดับสากลเมื่อใช้ portals ในแอปพลิเคชันที่ใช้งานจริง

ด้วยการเรียนรู้ React Portals อย่างเชี่ยวชาญ คุณจะสามารถยกระดับทักษะ React ของคุณไปอีกขั้นและสร้างเว็บแอปพลิเคชันที่ซับซ้อนและเป็นมิตรต่อผู้ใช้มากขึ้นสำหรับผู้ชมทั่วโลก