본문 바로가기

FrontEnd

리액트 디자인 패턴 : React Portal[리액트 포털/리액트 포탈]과 이벤트 버블링

반응형

portal with ReacT(jsX)

리액트 포털에는 재미있는 점이 몇 개 있습니다.

1. 컴포넌트 렌더링 위치와 돔 삽입 위치를 분리할 수 있습니다

리액트 트리 컴포넌트를 렌더링 위치와 실제 돔에 삽입되는 위치를 분리할 수 있습니다.

언뜻 보면 안티패턴 같아 보이지만,

데이터 관심사 중심으로 컴포넌트의 코로케이션(같이두기)가 가능해집니다.

데이터 중심 프로그래밍 관점에선 베리 굿입니다.

2. 렌더링 순서대로 컴포넌트가 자식으로 추가됩니다.

즉 portalNode의 1레벨 children으로 순서대로 추가됩니다.

주 : 개발환경에선 key를 지정해주지 않으면 자주 섞이는 것을 볼 수 있습니다

3. 컴포넌트 트리, 돔 트리 둘 중 한곳이 부모자식 관계면 이벤트 버블링을 이용할 수 있습니다.

아래와 같은 코드를 생각해 볼 수 있습니다.

포털 아이템은 이상한 곳에서 렌더링 되는것 같지만 모두 <Portal/>의 자식으로 렌터링 됩니다.

export default function App() {
  return (
    <div className="App">
      <h1>Hello Portal</h1>
      <PortalProvider>
        <h2>포탈은 아래에 있어요</h2>
        <PortalParent>
          <Portal />
        </PortalParent>
        <h2>포탈은 위에 있어요</h2>
        <div>
          <div>
            <PortalItem key="0">포탈 0</PortalItem>
          </div>
        </div>
        <div>
          <PortalItem key="1">포탈 1</PortalItem>
          <h2>나는 포탈 1의 아래에 있죠</h2>
        </div>
        <PortalItem key="2">포탈 2</PortalItem>





			{/* 다른 포탈 카운터*/}	
        <PortalParent>
          <PortalItem key="3">포탈 3</PortalItem>
        </PortalParent>
      </PortalProvider>
    </div>
  );
}

PortalParent 컴포넌트에게 이벤트 버블링을 캡쳐해서 포탈 클릭 횟수를 체크하도록 했습니다.

thisElement?.contains(event.target as HTMLElement)

1. 포탈 0,1,2,3 아무거나 클릭해도 클릭 횟수가 올라갑니다.

돔 트리 상에서 부모자식 관계이기 때문입니다.

이는 매우 정상적인 관계죠?

 

그리고 포탈 3의 경우, 별도의 PortalParent를 갖고 있으며, 문자에 3이 있을 경우 카운트를 올리도록 했습니다.

2. 포탈 3의 PortalParent는 Dom tree상 부모가 아님에도 이벤트 버블링의 대상이 됩니다.

이게 굉장히 특이합니다. 돔 트리 상의 부모가 아님에도, 컴포넌트 트리의 부모라는 이유만으로 클릭 이벤트를 전달받습니다.

 


결론

DOM 트리 상 부모 자식 관계가 아니더라도

컴포넌트 트리 상 부모 자식 관계일 때,

이벤트 버블링을 이용할 수 있다는 점을 이용하면

데이터 중심 코로케이션,

캡슐화를 효과적으로 달성할 수 있습니다.

 

이를 효과적으로 활용하는 방법은 다음 번에 다루도록 하겠습니다.

상당히 난이도가 높은 내용이 될 것 같습니다 --;

 

반응형