Rate this post

Portals là một tính năng mạnh mẽ trong React cho phép bạn render các phần tử con (child component) vào một node DOM khác nằm ngoài node DOM của component cha. Điều này hữu ích trong nhiều tình huống, chẳng hạn như khi bạn cần render một modal, tooltip, hoặc popover mà không bị ảnh hưởng bởi CSS overflow hoặc z-index của component cha. Bài viết này sẽ giúp bạn hiểu rõ hơn về Portals trong React, cách sử dụng và các trường hợp cụ thể nên áp dụng.

Portals là gì?

Định Nghĩa

Portals trong React cho phép bạn render các phần tử con vào một node DOM khác nằm ngoài node DOM của component cha. Điều này giúp bạn dễ dàng quản lý các thành phần UI phức tạp như modal, tooltip hoặc dropdown mà không gặp vấn đề về CSS.

Cách Hoạt Động

Portals không tạo ra một ngữ cảnh DOM mới; thay vào đó, chúng chèn các phần tử con vào một node DOM khác. Điều này có nghĩa là các phần tử con vẫn giữ nguyên ngữ cảnh React của chúng, bao gồm cả context và state.

Cách Sử Dụng Portals trong React

Tạo Node DOM

Đầu tiên, bạn cần tạo một node DOM trong file HTML của bạn. Thông thường, node này sẽ nằm ngoài root node chính của ứng dụng React.

Ví Dụ trong HTML

<!DOCTYPE html>
<html lang="en">
<head>
  <meta charset="UTF-8">
  <meta name="viewport" content="width=device-width, initial-scale=1.0">
  <title>React Portals Example</title>
</head>
<body>
  <div id="root"></div>
  <div id="portal-root"></div>
</body>
</html>

Sử Dụng ReactDOM.createPortal

Tiếp theo, sử dụng ReactDOM.createPortal để render component vào node DOM bạn đã tạo.

Ví Dụ với Portals

import React from 'react';
import ReactDOM from 'react-dom';

const Modal = ({ children }) => {
  const modalRoot = document.getElementById('portal-root');
  return ReactDOM.createPortal(
    <div className="modal">
      {children}
    </div>,
    modalRoot
  );
};

const App = () => {
  return (
    <div>
      <h1>Hello, React Portals!</h1>
      <Modal>
        <p>This is a modal rendered using React Portals.</p>
      </Modal>
    </div>
  );
};

export default App;

Styling Modal Component

Bạn có thể áp dụng CSS để định dạng modal component của mình.

Ví Dụ CSS

/* styles.css */
.modal {
  position: fixed;
  top: 50%;
  left: 50%;
  transform: translate(-50%, -50%);
  background-color: white;
  padding: 20px;
  box-shadow: 0 5px 15px rgba(0, 0, 0, 0.3);
  z-index: 1000;
}

Import CSS vào Component

import React from 'react';
import ReactDOM from 'react-dom';
import './styles.css';

const Modal = ({ children }) => {
  const modalRoot = document.getElementById('portal-root');
  return ReactDOM.createPortal(
    <div className="modal">
      {children}
    </div>,
    modalRoot
  );
};

const App = () => {
  return (
    <div>
      <h1>Hello, React Portals!</h1>
      <Modal>
        <p>This is a modal rendered using React Portals.</p>
      </Modal>
    </div>
  );
};

export default App;

Các Trường Hợp Sử Dụng Portals

Modal và Dialogs

Modal và dialogs thường cần được render trên top của các thành phần khác, không bị ảnh hưởng bởi CSS overflow hoặc z-index của component cha.

Ví Dụ Modal với Nút Đóng

import React, { useState } from 'react';
import ReactDOM from 'react-dom';
import './styles.css';

const Modal = ({ children, onClose }) => {
  const modalRoot = document.getElementById('portal-root');
  return ReactDOM.createPortal(
    <div className="modal">
      <button onClick={onClose}>Close</button>
      {children}
    </div>,
    modalRoot
  );
};

const App = () => {
  const [isOpen, setIsOpen] = useState(false);

  return (
    <div>
      <h1>Hello, React Portals!</h1>
      <button onClick={() => setIsOpen(true)}>Open Modal</button>
      {isOpen && (
        <Modal onClose={() => setIsOpen(false)}>
          <p>This is a modal rendered using React Portals.</p>
        </Modal>
      )}
    </div>
  );
};

export default App;

Tooltip và Popover

Tooltip và popover cũng là các thành phần UI phổ biến cần được render ngoài node DOM của component cha để đảm bảo hiển thị chính xác.

Ví Dụ Tooltip

import React from 'react';
import ReactDOM from 'react-dom';
import './styles.css';

const Tooltip = ({ children, targetRef }) => {
  const tooltipRoot = document.getElementById('portal-root');
  const { top, left, width } = targetRef.current.getBoundingClientRect();
  const style = {
    position: 'absolute',
    top: `${top - 30}px`,
    left: `${left + width / 2}px`,
    transform: 'translateX(-50%)',
    backgroundColor: 'black',
    color: 'white',
    padding: '5px 10px',
    borderRadius: '4px',
  };

  return ReactDOM.createPortal(
    <div style={style}>
      {children}
    </div>,
    tooltipRoot
  );
};

const App = () => {
  const targetRef = React.createRef();

  return (
    <div>
      <h1>Hello, React Portals!</h1>
      <button ref={targetRef}>Hover me</button>
      <Tooltip targetRef={targetRef}>
        Tooltip Content
      </Tooltip>
    </div>
  );
};

export default App;

Những Lưu Ý Khi Sử Dụng Portals

Quản Lý Sự Kiện

Khi sử dụng Portals, các sự kiện vẫn được quản lý theo ngữ cảnh React của chúng, bao gồm cả sự kiện con trỏ (pointer events) và bàn phím (keyboard events).

Kiểm Soát Z-Index

Đảm bảo rằng các phần tử render qua Portals có giá trị z-index phù hợp để hiển thị trên các phần tử khác của ứng dụng.

Sử Dụng Context

Context vẫn hoạt động bình thường với Portals. Các phần tử được render qua Portals vẫn có thể truy cập vào context của component cha.

Kết Luận

Portals trong React là một công cụ mạnh mẽ giúp bạn dễ dàng quản lý các thành phần UI phức tạp như modal, tooltip và popover. Bằng cách sử dụng Portals, bạn có thể đảm bảo rằng các thành phần này được hiển thị đúng cách mà không gặp vấn đề về CSS overflow hoặc z-index. Hãy thử áp dụng các kỹ thuật này trong dự án của bạn để tận dụng tối đa sức mạnh của Portals trong React.

Tham Khảo

  1. React Documentation on Portals
  2. MDN Web Docs on HTML DOM
  3. CSS Tricks on Modals
  4. FreeCodeCamp Guide to React Portals
  5. Blog Posts and Tutorials on Medium

Để lại một bình luận

Email của bạn sẽ không được hiển thị công khai. Các trường bắt buộc được đánh dấu *

Contact Me on Zalo
Call now