+8

React Portal và ứng dụng hữu ích của nó

Trong lúc phát triển dự án về web cùng với react các bạn đã nghĩ đến việc show một modal full màn hình hay show một notification ở góc màn hình và đặt chúng ở đâu trong DOM chưa? Ở trong bài này tôi sẽ giúp bạn tìm ra giải pháp đó.

React Portals là gì?

Đây chính là giải pháp mà tôi muốn chia sẻ React Portals sẽ giúp bạn giải quyết được vấn đề ở trên, Nó cho phép bạn tạo ra component bên ngoài app của bạn hay nói cách khác là bên ngoài thẻ <div id="root"></div> nhưng nó vẫn giữ được các state và bạn vẫn có thể sử dụng đồng thời truyền những props vào như một component bình thường vậy mà vị trí trong DOM có thể ở bất cứ đâu.

Vậy sử dụng nó như thế nào?

Trước tiên ở thư mục index.html bạn cần thêm 1 thẻ như sau:

<div id="portal"></div>

Thẻ này sẽ chứa tất cả nhưng component nào mà bạn không muốn nó xuất hiện trong DOM của <div id="root">.

Tiếp theo bạn cần tạo một portal để chứa các component alert hoặc notification của mình. portal > index.jsx

import React from "react";

const Portal = ({ children }) => {
  const domElement = document.getElementById('portal');

  return (
    ReactDOM.createPortal(children, domElement)
  );
}

export default Portal;

Bây giờ bạn chỉ cần tự tạo cho mình một cái notification thật xịn xò và đẹp đẽ sau đó apply vào portal nữa là xong rồi.

notification > index.jsx

import React from "react"
import Portal from '../portal'

const Notification = ({
  children,
  autoClose = 3000,
  onClose,
}) => {
  const [isClose, setIsClose] = React.useState(false)

  React.useEffect(() => {
    const timerId = setTimeout(() => setIsClose(true), autoClose)

    return () => {
      clearTimeout(timerId)
    }
  }, [autoClose])

  const animationEnd = () => {
    if (isClose) onClose()
  }

  return (
    <Portal>
        <div className={`container ${isClose ? "close" : "open"}`} onAnimationEnd={animationEnd}>
          <div className="container__icon">
                Icon
          </div>
          <p className="container__message">{children}</p>
          <div className="container__close" onClick={() => setIsClose(true)}>
              x
          </div>
        </div>
    </Portal>
  )
}

export default Notification

notification > style.css

.container {
  width: 350px;
  min-height: 65px;
  display: flex;
  align-items: center;
  background-color: #2BDE3F;
  position: fixed;
  top: 40px;
  right: 0;
  z-index: 300;
  border-top-left-radius: 6px;
  border-bottom-left-radius: 6px;
  overflow: hidden;  
}

@keyframes fadeOut {
  0% {
    transform: translateX(0) rotateY(0) scale(1);
    transform-origin: -1800px 50%;
    opacity: 1;
  }
  100% {
    transform: translateX(1000px) rotateY(-30deg) scale(0);
    transform-origin: -100% 50%;
    opacity: 0;
  }
}

@keyframes fadeIn {
  0% {
    transform: translateX(1000px) rotateY(-30deg) scale(0);
    transform-origin: -100% 50%;
    opacity: 0;
  }
  100% {
    transform: translateX(0) rotateY(0) scale(1);
    transform-origin: -1800px 50%;
    opacity: 1;
  }
}

.close {
  animation: fadeOut 0.7s cubic-bezier(0.25, 0.46, 0.45, 0.94) both;
}

.open {
  animation: fadeIn 0.7s cubic-bezier(0.25, 0.46, 0.45, 0.94) both;
}

.container__message {
  flex: 1;
  padding: 10px 26px 10px 10px;
  color: white;
  font-weight: bolder;
  font-size: 14px;
  line-height: 1.5;
}

.container__icon {
  width: 65px;
  height: 65px;
  display: flex;
  align-items: center;
  justify-content: center;
  color: white;
  background-color: #0a6314;
}

.container__close {
  display: flex;
  justify-content: center;
  align-items: center;
  width: 24px;
  height: 24px;
  border-radius: 4px;
  color: white;
  background-color: rgba(0, 0, 0, 0.4);
  position: absolute;
  top: 4px;
  right: 4px;
  cursor: pointer;
}

Giờ chỉ việc show ra thành quả thôi nào

import React from "react";
import Notification from "./notification"

function App() {
  return (
    <div>
         <h1>Hello Bro !!!</h1>
         <Notification>This is notification</Notification>
    </div>
  );
}

export default App;

Trên đây là một ví dụ nhỏ về ứng dụng của React Portals. Bạn có thể áp dụng tương tự cho Modal hoặc là Tooltip chẳng hạn.

Nếu muốn tìm hiểu kĩ càng hơn về nó thì hãy vào đây nhé ✌️


All rights reserved

Viblo
Hãy đăng ký một tài khoản Viblo để nhận được nhiều bài viết thú vị hơn.
Đăng kí