리액트를 시작한지 어언 5개월차.. 매번 쓰던 hook 말고도 다른 기능들을 독학하기로 결심했다.
그중 리액트 포탈이라는 것을 보고 여기 정리해두고자 한다.
리액트의 기능 중 하나인 Portal 포탈은 부모 컴포넌트의 DOM 계층 구조 바깥에 있는 DOM 노드로 자식을 렌더링하는 최고의 방법을 제공.. 한다고 공식 문서에 명시되어 있다.
Portals – React
A JavaScript library for building user interfaces
ko.reactjs.org
쉽게 말하자면 객체를 생성했다가 원하는 DOM 위치에 추가해주는 기능을 가지고 있다.
때문에 팝업이나 툴팁처럼 같은 스타일의 컴포넌트를 여러 페이지에서 돌려막기? 할 때에 유용하게 쓰일 것 같다.
우선 마크업은 대충 요렇게 짜봤다.
App.js
import './App.css';
import { useState, useRef } from 'react'
import Portals from './Portals';
function App() {
const data = [{
key: 1,
title: 'HTML',
desc: '마크업 기본'
}, {
key: 2,
title: 'css',
desc: '스타일 정의'
}, {
key: 3,
title: 'javascript',
desc: '함수 적용'
}]
const popOverRef = useRef([]);
const [currentIdx, setCurrentIdx] = useState()
return (
<div className="App">
{data.map((item, idx) => {
return (
<div
className="lists"
key={item.key}
ref={el => popOverRef.current[idx] = el}
onClick={() => setCurrentIdx(idx)}>
<div>{item.title}</div>
</div>
)
})}
<Portals target={popOverRef.current[currentIdx]}>
<p className="tooltip">{data[currentIdx]?.desc}</p>
</Portals>
</div>
);
}
export default App;
여러 데이터를 예시로 (일단 3개..) 넣어 두고 map으로 돌렸다. 여기서 중요한 점은 여러개의 엘리먼트를 ref로 저장한 점과 엘리먼트를 클릭할 때마다 currenIdx라는 state를 변경한 것이다.
data[currentIdx] 뒤에 ?를 붙인 이유는, 맨처음 화면이 렌더될때 currentIdx 값이 없으므로 오류를 방지하기 위해 넣었다.
createPortal은 'Portals'라는 별도의 컴포넌트로 분리시켜서 불렀다.
Portals.js
import { createPortal } from 'react-dom'
const Portals = ({ children, target }) => {
// console.log(children, target)
return target ? createPortal(children, target) : null
}
export default Portals
createPortal은 2개의 인자를 보낸다. 첫번째는 렌더될 자식 요소로, DOM엘리먼트나 문자열 등등 뭐든 렌더링될 만한 애들은 다 넣을 수 있다. 두번째는 렌더시킬 위치, DOM 엘리먼트를 넣는다.
createPortal(렌더할 자식놈들, 렌더될 타겟 위치)
앞서 ref를 맵핑된 객체마다 넣어준 이유는 바로 이 target(두번째 인자)으로 넘기기 위함이었다.
클릭 할 때마다 target이 바뀌므로 target 값에 따라 해당 dom이 아닐때는 null값으로 리턴하도록 짰다.
children은 Portals 컴포넌트 자식으로 넣어둔 p태그가 넘겨진다. 나는 간단하게 p태그로 짰지만, 팝업처럼 구조도 다양하고 콘텐츠도 많아 지면, 이 부분도 컴포넌트화 해서 따로 만들어 넣어도 좋겠다.
초 간단하게 짠거라 별건 없지만 참고차 css도 올린다.
App.css
.App {
max-width: 800px;
margin: 0 auto;
text-align: center;
}
.lists {
position: relative;
padding: 40px 0;
border: 1px solid #222;
border-bottom: 0;
}
.lists:last-child {
border-bottom: 1px solid #222;
}
.tooltip {
position: absolute;
right: 10px;
top: 50%;
transform: translateY(-50%);
border: 1px solid #999;
padding: 5px 8px;
margin: 0;
font-size: 12px;
background-color: #d8f5fd
}

portals 한번 써봤는데 꽤 매력있는 거 같다. 라이브러리 안 쓰고 급하게 간단한 용도로 필요할 때 이용하면 좋을거 같다.
'React' 카테고리의 다른 글
react-router-dom v5에서 link로 이동시 화면이 redirecting 되지 않음.. (0) | 2022.08.30 |
---|---|
[Redux] 컴포넌트에서 connect로 ownProps 받을 때 컴포넌트 props 값 모두 받아오기 (0) | 2022.08.26 |
React에서 (api 데이터) json형식 데이터 가져오기 및 원하는 데이터 추출 등 데이터 관리 방법! (0) | 2022.03.05 |