
복합 차트의 자유도를 찾아서
최근에 거래 지표 시각화에 관한 요구사항이 있었다.
거래량, 토큰가격 등의 다양한 거래 지표를 한 그래프(좌표계) 위에 동시에 그려넣는 것이었고, 이는 일반적인 단일 그래프와는 완전히 다른 접근법이 필요했다.
결론적으로 복합차트 렌더링을 지원하는 라이브러리를 비교/분석해야 했고, 최종 선택한 reaviz의 높은 자유도 뒤에 숨겨진 트레이드오프를 맞닥뜨리게 되었다.
구현해야했던 복합차트 3종의 요구스펙은 다음과 같았다.
- 차트 1: 매수와 매도 잔량을 좌우로 분리해서 렌더링함. Depth Chart
- 차트 2: 3개의 서로다른 거래 지표를 서로 다른 형태로 렌더링함. 거래량(Bar), 이동평균선(Line), 체결 내역(Scatter)
- 차트 3: n개 가격 추이를 겹쳐서 렌더링함. 다중 라인 차트

차트1: Depth Chart, 매수/매도
매수와 매도 잔량을 좌우로 분리해서 렌더링함

차트2: 거래량(Bar) + 이동평균선(Line) + 체결 내역(Scatter)
3개의 서로다른 거래 지표를 서로 다른 형태로 렌더링함.

차트3: n겹 다중 라인 차트
n개 가격 추이를 겹쳐서 렌더링함.
기술선정: Reaviz를 선정한 근거
적합한 라이브러리를 찾기 위해 react생태계에서 점유율이 높은 라이브러리들을 우선 검토했다. recharts, ApexCharts, victory 등 이외에도 여러 차팅 라이브러리를 리서치를 해야했다.
이후 기능적 지원 여부를 따지며 recharts, ApexCharts, victory, reaviz 4가지 비교군으로 좁히게 됐다.
위 라이브러리들은 공통적으로 “시작하기 쉬운 조건”을 갖고 있다.
여기서 말하는 시작하기 쉬운 조건이란 아래와 같다.
- 특별한 설정 없이 데이터만 넘기면 차트를 알아서 잘 그려줌
- 사용자가 많고, 관련 문서/자료가 많음
- 구현 난이도가 낮음.
이런 류의, 생태계가 잘 갖춰진 라이브러리는 대체로 대부분의 기능을 사용하기 쉬운 형태로 제공해줘서 만능처럼 보이기도 하지만, "복합 차트"를 구현하기에는 기능적 제약사항이 존재했다. 대부분 "시작하기 쉬운 조건"에만 집중되어 있었고 각 지표별 데이터를 개별적으로 다루는 데에 있어서는 불가능하거나 제약사항이 컸다
recharts, ApexCharts등은 라인그래프와 바그래프를 한 화면에 렌더하는 것이 불가능했고, 라인차트로 동시에 2개를 복합 렌더하더라도 툴팁까지 분리하는 것은 불가능했다.
* 복합차트란 다양한 데이터 지표를 하나의 좌표계 위에 그리는 것을 말한다.
우리 팀에 필요했던 건 위와같은 "시작하기 쉬운 조건"이 아니라, "자유도"이었다
d3.js수준의 자유도를 가지되, 생산성이 높을 것. 과하게 어렵지 않아야함- 복합 차트 구현에 유연해야함
그래서 “자유도”을 최우선 기준으로 다시 비교 및 리서치한 결과, 최종적으로 reaviz 라는 차팅 라이브러리를 선정했다.
reaviz의 조립하는 구조
Reaviz는 차트의 뼈대가 되는 ChartContainer 를 부모로 두고, 그 아래 자식으로 BarSeries, LineSeries 같은 다양한 Series 컴포넌트들을 조립하며 선언적으로 다룰 수 있는 게 특징이다.
막대그래프 차트가 필요하면 BarSeries 컴포넌트를 사용하면 됐고, 그 위에 중첩으로 라인그래프가 필요하면 LineSeries 컴포넌트만 형제자리(sibling)으로 두면 되는 구조였다.
reaviz에서 대부분의 차트 컴포넌트가 이렇게 독립적으로 분리되어 있다 보니, 내가 원하는 모든 형태로 레이어를 쌓아 올릴 수 있다...!
하지만 막상 개발 깊숙이 들어가자, 이 유연함 뒤에 숨겨진 명확한 단점, 트레이드오프를 마주하게 되었다.
단점 1: 예측하기 힘든 내부구현
reaviz는 컴포넌트 props에 원하는 데이터 형태를 전달받고 렌더하는 방식이다. props로 전달받는 타입 중에 jsx를 받는 곳도 상당히 많다.
그런데 특이한 점은 상태공유를 위한 Provider가 없고 오로지 프레젠테이션 계열의 컴포넌트 조합만으로 동작한다는 점이다.
이런 이유로 reaviz의 내부 소스코드는 아래로 상태 전달을 하기 위해 props drilling이 빈번했고, 이게 동작 예측을 굉장히 어렵게 만드는 만드는 주범이었다.
내부 코드에서 간혹 cloneElement를 남용하는 모습이 보이기도 했다. 컴포넌트에 props을 넘겨주면면, 전달받은 값이 우선되어야 함에도 불구하고 cloneElement의 효과로 인해 원하는 형태 또는 동작이 덮어씌워지는 경우가 생기는 경우도 발생했다.
아래 예시코드에서 disabled 를 전달하면 툴팁이 예상처럼 비활성화 상태로 바뀌지 않는다.
<AreaSeries
// ... 생략
tooltip={
<TooltipArea
tooltip={
<ChartTooltip
disabled={true} 👈👈
content={() => <div>Tooltip ontent</div>}
/>
}
/>
}
/>약식 코드이지만, 실제로 disabled가 내부코드에서 무시된 채 툴팁이 버젓이 렌더링 되는 문제를 안고있다.
역시나 이유는 부모인 TooltipArea가 내부에서 cloneElement를 사용해 자식을 복제하는데, 이 과정에서 disabled 속성이 강제로 덮어씌워지기 때문이다. props는 전달받은 그대로 존중해주어야하는데, 무시되는 곳이 있으리라고는 예상하지 못했다.
단점 2: 생각보다 빈약한 문서
동작이 예상과 다르니 디버깅을 하려 문서를 뒤적이게 됐는데, 여기서 두 번째 문제점을 맞닥뜨렸다.
"공식 API 문서가 조금 빈약하다". API의 기본 설명은 잘 되어있지만, 상세 디테일은 없거나 빠진 부분이 일부 있었다.
원하는 형태로 커스터마이징 하기 위해 결국은 소스코드를 열어보며 해결해야 했다.
Claude에 학습시키면 그나마 쉽게 해결되는 지점이 많았지만 그래도 문서가 얇은 점은 API 소비 측면에서 정말 아쉬웠다...!
단점 3: DX를 위해 포기된 내부 코드
내부 구현, 설계에 관한 호기심이 생겨 내부 코드를 천천히 읽어보는 시간을 가져본 적이 있는데, 이때 reaviz의 설계 방향과 그 흐름에 대해 이해하고 공감해볼 수 있었다.
정리하면, 내가 겪던 것은 단순 버그보다도, "자유도"를 얻기 위해 포기되었던 "구조적 안정성"으로 인한 트레이드오프였다.
Reaviz는 거의 모든 컴포넌트가 Provider 의존성이 없다. 즉, 차트를 그릴 때 Provider를 신경쓰지 않고 단순 UI컴포넌트만 조립하면 완성할 수 있는 형태로 구현이 가능했다.
그러나 파생된 문제점은 결국 조상->손자 간의 상태 전달을 위해 cloneElement 같은 무리한 패턴이 사용되었다.
그 반대로 유명 라이브러리들인 Recharts, Victory등은 Provider 의존성이 강한 편이다. reaviz처럼 단순 조립식의 DX를 가질 수 없고, props를 굉장히 많이 받는 뚱뚱한 컴포넌트가 존재하는 것도 이 이유일 것이다.
TooltipArea 버그와 기여
Reaviz를 서비스에 붙이고 나니 예상치 못한 버그도 몇 번 나왔다. 그중 가장 인상적이었던 건 툴팁 위치 증발 이슈였다.

재현 조건
차트 위에 툴팁이 떠 있는 상태에서 Cmd+Tab으로 다른 앱에 다녀오면, 툴팁이 갑자기 화면 좌상단(0,0) 좌표로 튀어버린다.
원인 분석
근본적인 원인은 툴팁의 visible 상태가 바뀔 때 컴포넌트의 Mount/Unmount가 반복되는 데 있었다.
툴팁 컴포넌트가 다시 마운트될 때, 이전의 내부 상태(특히 마우스 위치 컨텍스트)를 잃어버리면서 기본 좌표값인 (0,0)으로 초기화되는 것이었다. (물론 이후 마우스를 살짝이라도 움직이면 다시 정상 위치로 돌아온다.)
대응
사용자 경험(UX) 관점에서 그냥 넘기기엔 너무 어색한 버그였다. 결국 코드를 파고들어 해당 로직을 수정했고, PR을 올려둔 상태다.
(PR: https://github.com/reaviz/reaviz/pull/312)
정리.. 자유도와 DX는 같은 축에 있지 않다
Reaviz는 “자유로운 커스터마이징”이라는 목표에는 확실히 성공했다고 본다.
하지만 그만큼의 대가로 개발자가 치러야 할 Trade-off가 컸고, DX 관점에서는 아쉬움이 남았다.
"이번 경험을 통해 자유도와 DX는 반비례 관계에 가깝다는 것을 뼈저리게 배웠다."
다음에 다시 비슷한 요구사항을 받는다면, 나는 이런 기준으로 결정할 것이다.
- 복합 차트를 아주 강하게 커스텀해야 한다. →
Reaviz - 예측 가능성과 안정적인 DX가 최우선이다. →
Recharts같은 전통적인 선택지
Written on
2025-11-09 09:25
