티스토리 뷰

728x90
SMALL

배경

react는 기본적으로 state와 props로 데이터를 관리한다. 그리고 props로 데이터를 몇 단계씩 넘기다보니 데이터 관리가 너무 어려워졌다. 이를 props 드릴링이라고 부른다. 이 props 드릴링 문제를 해결하기 위해서 redux같은 상태관리 라이브러리를 도입해서 해결했다. 그러면 이제 모든게 행복하게 해결된걸까? 전역상태관리라이브러리에 접근해서 의존성주입없이 데이터와 UI가 강결합되었다. 이게 결코 옳은 방향은 아니다.

 

presentation component와 container component

과거부터 데이터와 UI를 분리하려는 노력은 계속되어왔다. 과거 리액트는 리덕스를 사용하는게 거의 표준이였다. 그리고 리덕스와 함께 presentation component와 container component를 분리해서 컴포넌트를 만들었다. 그리고 나도 우아한테크캠프 마지막 프로젝트에서 이 패턴으로 개발을 했었다. 데이터와 UI를 컴포넌트로 분리하다보니 프로젝트가 복잡해질수록 props 드릴링이 심각하게 일어났다. 그럼에도 불구하고 이 패턴은 과거 표준처럼 사용되던 패턴이였고 이런 패턴은 현재도 많이 사용된다.

 

지금까지 상황을 정리해보면 다음과 같다.

react에서 props 드릴링 문제 발생 => redux 도입 => redux에서 presentation component와 container component 패턴 도입 => props 드릴링 문제 발생

 

리액트 훅의 등장

클래스 컴포넌트를 사용하던 리액트에서 함수형 컴포넌트와 훅이 도입되었다. 과거 HOC를 사용하는 부분도 훅으로 대체할 수 있게 되었다. 뿐만 아니라 데이터를 훅으로 관리할 수 있게 되었다. 즉 불필요한 props 드릴링이 사라지고 훅으로 대체될 수 있다.

 

과연 그럴까? 과거에는 이런 글을 보고 그렇구나 라고 생각한적도 있었지만 조금만 생각해보면 그렇지 않다는 것을 알게된다. 

 

비록 코드상에서는 데이터와 UI를 분리했을지라도 컴포넌트입장에서는 그렇지 않다. 어쨋든 UI와 데이터가 결합된 컴포넌트다. (물론 훅으로 데이터를 분리하는 것만으로도 의미가 있고 순수한 UI가 필요해졌을 때 데이터 로직을 props로 이동하는 것도 가능하기는 하다.)

 

결국 순수하게 데이터와 UI를 분리하기 위해서는 다시 과거로 돌아와서 presentation component와 container component의 분리가 필요하다.

 

다시 원점으로 돌아가서 생각해보기

돌고돌아서 다시 원점으로 돌아왔다. 훅의 도입으로 데이터 분리가 용이해졌지만 그게 모든 것을 해결해주지는 못한다는 것을 알았다.

 

잠깐 다른 얘기를 하겠다. 나는 SICP라는 책으로 스터디를 한적이 있다. 그리고 이 책에서 추상화 장벽이라는 얘기가 나온다.

 

추상화 장벽 

- 추상화 장벽 위에 있는 프로그램은 그 아래 있는 프로그램의 데이터 추상들을 활용한다. 

- 전체 시스템에서 쌍 객체 장벽보다 위에 있는 프로그램들은 쌍 객체를 그냥 조작할 뿐, 쌍 객체가 어떻게 구현되는지는 알지 못하고 알 필요도 없다. 

- 본질적으로 각 수준의 함수들은 추상화 장벽을 정의하고 서로 다른 수준들을 연결하는 인터페이스로 작용한다. 추상화 장벽의 장점 프로그램을 관리(유지보수)하고 수정하기가 훨씬 쉽다. 그 어떤 복잡한 자료구조라도 원시 자료 구조를 이용해서 다양한 방식으로 표현할 수 있다.

 

리액트와 컴포넌트, props 드릴링을 생각하다가 문득 추상화장벽 생각이 났다. 추상화 장벽 관점에서 보면 각각의 컴포넌트들은 추상화장벽으로 이루어지고 인터페이스로 통신한다. 다만 리액트에서 컴포넌트를 다룰 때는 props가 너무 깊어지는 문제가 발생하는데 이 경우만 해결하면 된다. props를 내려주는 것 자체는 전혀 문제가 없다.

 

6계층의 props 드릴링이 필요한 컴포넌트가 존재한다고 가정해보자. 이 때 1계층과 4계층에서만 전역 데이터를 불러오면 어떨까? 그러면 2, 3, 5, 6 계층은 순수한 UI 컴포넌트가 된다. (4가 1과6의 중간이라서 그런건 아니고 적당한 중간 계층을 찾아서 적용하면 될 것 같다.)

 

예시

나는 최근 트리 컴포넌트를 만들었다. 트리 컴포넌트는 headless로 되어있고 각각의 트리는 renderItem이라는 함수로 연결할 수 있다.

(코드를 공개할 수 없으니 atlassian트리의 renderItem을 생각하면 된다.)

각각의 renderItem는 Menu-a와 Menu-b를 조합해서 만들어진다.

Menu-a는 데이터에 따라 여러 컴포넌트를 조합해서 만들어진다.

Menu-b는 데이터에 따라 컴포넌트가 다르다.

또한 Menu-b에서 모달을 띄우는 로직이 존재한다.(모달도 여러개고 전달되는 데이터도 다르다.)

그리고 또한 Menu-b의 모달에서 데이터가 필요하다.

또 Menu-b의 모달에서 n개의 중첩된 모달을 띄울 수 있다.

 

정리해보면 Tree renderItem > Menu-a, Menu-b > 모달1 > 모달2 > 모달3 이런형태다. 

모달이 3개라고 가정했을 때 props를 4번씩이나 내려줘야한다. 나는 컴포넌트를 최대한 깊게 만들지 않았고 데이터가 필요한 곳에서 데이터를 불러왔다. 그런데도 깊은 props 드릴링이 발생했다. 분명히 일반적인 경우는 아니다. 하지만 누구나 겪을수있는 문제다.

 

이런 경우에 나는 모달1에서 전역 데이터에 접근을 시켰다. n개의 중첩된 모달을 띄워야한다면 말만 모달이지 복잡한 페이지의 형태를 띄고 있다고 생각한다. 각각의 모달1에서 전역 데이터를 불러오게 되면 페이지같은 큰 모달 컴포넌트에서만 데이터와 UI가 결합되고 하위 모달 컴포넌트에서는 순수한 UI를 가지는 컴포넌트가 만들어지게 된다.

 

조금 다른 예시를 들어보겠다. 페이지에서 특정 버튼을 눌러서 rightPanel을 띄운다고 생각해보자. 이건 기존의 페이지 컴포넌트와 독립적으로 데이터를 다뤄도 크게 이상해보이지 않는다. (물론 페이지에서 props를 내려줄수도있다. 하지만 그정도는 넘어가자. 더 깊게 나가면 페이지에서 전역데이터에 접근하지 말고 라우터단에서 props로 전달해야되니까..)

 

결론

아무리 컴포넌트를 수평적으로 만들고 필요한 곳에서 데이터를 사용해도 데이터와 UI를 분리하려면 props 드릴링은 피할 수 없다.

데이터와 UI는 props 드릴링을 감수하면서도 해볼만한 가치가 있다.

경우에 따라선 특정 컴포넌트를 데이터와 UI를 결합시키자. 그리고 훅으로 최대한 데이터를 격리시키자.

중요한건 상황에 따라 적절히 유연하게 대응하는 것이다. 데이터와 UI를 결합시키는 것도 절대 잘못된 방법이라고는 할 수 없다. 그저 여러가지 장단점을 가진 방법중 하나일뿐...

728x90
LIST
댓글
공지사항