Portfolio 2026년 2월 22일
React 기반 대시보드 - 실시간 데이터 시각화 플랫폼

React 기반 대시보드 - 실시간 데이터 시각화 플랫폼

실시간 데이터 스트리밍 및 인터랙티브 시각화를 위한 React 대시보드

#React #TypeScript #D3.js #WebSocket #Material-UI

image: “/images/projects/react-dashboard.png”

프로젝트 개요

이 프로젝트는 실시간 데이터 스트리밍과 인터랙티브 시각화 기능을 제공하는 React 기반 대시보드입니다. 금융 데이터를 실시간으로 수집하고, 사용자가 직관적인 UI로 데이터를 분석할 수 있는 플랫폼을 구축했습니다.

주요 목표:

  • 초당 100개 이상의 데이터 포인트를 실시간으로 렌더링
  • 반응형 디자인으로 다양한 디바이스 지원
  • 커스터마이징 가능한 차트 및 위젯 시스템

기술 스택

카테고리기술
프레임워크React 18, TypeScript 5.x
상태 관리Redux Toolkit, RTK Query
시각화D3.js, Recharts
UI 라이브러리Material-UI v5, Emotion
실시간 통신WebSocket, Socket.io
빌드 도구Vite 5.x
테스트Jest, React Testing Library

주요 기능

1. 실시간 데이터 시각화

WebSocket을 통해 실시간으로 데이터를 수신하고 D3.js를 사용하여 동적 차트를 렌더링합니다. 가상 스크롤링 기능을 적용하여 대량 데이터를 효율적으로 표시합니다.

// 실시간 데이터 수신 커포넌트
import { useEffect, useState } from 'react';
import { useWebSocket } from '@/hooks/useWebSocket';

const RealTimeChart: React.FC = () => {
  const [data, setData] = useState<DataPoint[]>([]);
  const { socket, isConnected } = useWebSocket('wss://api.example.com/stream');

  useEffect(() => {
    socket.on('message', (newData: DataPoint) => {
      setData(prev => [...prev.slice(-100), newData]); // 최근 100개만 유지
    });

    return () => socket.off('message');
  }, [socket]);

  return <LineChart data={data} />;
};

2. 커스터마이징 위젯 시스템

사용자가 대시보드 레이아웃을 직접 구성할 수 있는 드래그 앤 드롭 기능을 제공합니다.

// 위젯 레이아웃 컨테이너
import { useDroppable } from '@dnd-kit/core';
import { SortableContext, verticalListSortingStrategy } from '@dnd-kit/sortable';

const WidgetContainer: React.FC = () => {
  const { setNodeRef } = useDroppable({ id: 'dashboard' });
  const { widgets } = useAppSelector(state => state.dashboard);

  return (
    <div ref={setNodeRef} className="dashboard-container">
      <SortableContext items={widgets} strategy={verticalListSortingStrategy}>
        {widgets.map(widget => (
          <SortableWidget key={widget.id} widget={widget} />
        ))}
      </SortableContext>
    </div>
  );
};

3. 성능 최적화

  • React.memo: 불필요한 리렌더링 방지
  • useMemo & useCallback: 계산 비용이 높은 연산 최적화
  • Web Workers: 차트 렌더링 계산을 백그라운드로 처리
// 메모이제이션 예시
const memoizedChart = React.memo<ChartProps>(({ data, config }) => {
  const chartData = useMemo(() => processData(data, config), [data, config]);

  return <D3Chart data={chartData} />;
}, (prev, next) => {
  return prev.data.length === next.data.length && prev.config === next.config;
});

개발 과정

1. 초기 설계 (1주)

  • 사용자 요구사항 분석 및 와이어프레임 작성
  • 컴포넌트 구조 설계 및 상태 관리 전략 수립
  • 기술 스택 선정 (React vs Vue, Redux vs Zustand)

2. MVP 개발 (2주)

  • 기본 차트 컴포넌트 구현
  • WebSocket 연결 및 데이터 파이프라인 구축
  • 기본 UI 레이아웃 완성

3. 기능 확장 (3주)

  • 위젯 시스템 구현
  • 다크 모드 및 테마 기능 추가
  • 필터링 및 검색 기능 구현

4. 성능 최적화 (1주)

  • 렌더링 성능 프로파일링
  • 메모리 누수 수정
  • 번들 사이즈 최적화 (12MB → 2.4MB)

문제 해결 과정

문제 1: 대량 데이터 렌더링 성능 저하

문제: 초당 100개 이상의 데이터가 들어올 때 UI가 멈추는 현상 발생

원인 분석:

  • 전체 데이터 배열을 매번 순회하며 차트를 다시 그리는 과정에서 병목
  • DOM 업데이트가 너무 잦음

해결책:

// 가상 스크롤링 적용
import { useVirtualizer } from '@tanstack/react-virtual';

const VirtualizedChartList: React.FC = () => {
  const parentRef = useRef<HTMLDivElement>(null);
  const virtualizer = useVirtualizer({
    count: data.length,
    getScrollElement: () => parentRef.current,
    estimateSize: () => 50,
    overscan: 10,
  });

  return (
    <div ref={parentRef} style={{ height: '600px', overflow: 'auto' }}>
      {virtualizer.getVirtualItems().map(item => (
        <ChartItem key={item.key} data={data[item.index]} />
      ))}
    </div>
  );
};

결과: 렌더링 시간 800ms → 16ms로 개선 (FPS 60 유지)

문제 2: WebSocket 연결 끊김 처리

문제: 네트워크 불안정 시 자동 재연결이 되지 않음

해결책:

// 자동 재연결 로직
class WebSocketService {
  private ws: WebSocket | null = null;
  private retryCount = 0;
  private maxRetries = 5;
  private retryDelay = 1000;

  connect() {
    this.ws = new WebSocket('wss://api.example.com/stream');
    this.ws.onclose = () => this.handleReconnect();
    this.ws.onerror = () => this.handleReconnect();
  }

  private handleReconnect() {
    if (this.retryCount < this.maxRetries) {
      setTimeout(() => {
        this.retryCount++;
        this.connect();
      }, this.retryDelay * this.retryCount);
    }
  }
}

성과와 배운 점

성과

  • 사용자 경험: 페이지 로드 시간 3.2초 → 0.8초로 개선 (75% 감소)
  • 성능: 1,000개 데이터 포인트 렌더링 시 60 FPS 유지
  • 사용자 만족도: 4.5/5점 별점 평가

배운 점

  1. 성능 최적화의 중요성: 초기 설계 단계에서 성능을 고려해야 함
  2. TypeScript의 가치: 런타임 에러를 90% 이상 사전에 방지
  3. 상태 관리 패턴: Redux Toolkit은 복잡한 상태 관리에 적합
  4. 실시간 데이터 처리: WebSocket과 Polling의 장단점 이해

코드 스니펫

RTK Query를 활용한 서버 상태 관리

// api/dashboardApi.ts
import { createApi, fetchBaseQuery } from '@reduxjs/toolkit/query/react';

export const dashboardApi = createApi({
  reducerPath: 'dashboardApi',
  baseQuery: fetchBaseQuery({ baseUrl: '/api' }),
  tagTypes: ['Dashboard', 'Widget'],
  endpoints: (builder) => ({
    getDashboardData: builder.query<DashboardData, void>({
      query: () => '/dashboard',
      providesTags: ['Dashboard'],
    }),
    updateWidget: builder.mutation<Widget, Partial<Widget>>({
      query: (body) => ({
        url: '/widgets',
        method: 'PUT',
        body,
      }),
      invalidatesTags: ['Dashboard'],
    }),
  }),
});

export const { useGetDashboardDataQuery, useUpdateWidgetMutation } = dashboardApi;

향후 개선 계획

  • 오프라인 모드 지원 (Service Worker)
  • 데이터 내보내기 기능 (CSV, PDF)
  • 사용자별 커스텀 대시보드 저장
  • 머신러닝 기반 이상 탐지 알림

GitHub: https://github.com/username/react-dashboard Demo: https://react-dashboard-demo.vercel.app