왜 ReactFlow 엣지가 Next.js에서 사라지는가 (두 가지 미묘한 CSS 및 Context 버그)

발행: (2026년 3월 31일 AM 12:35 GMT+9)
9 분 소요
원문: Dev.to

Source: Dev.to

nareshipme

우리는 지식 그래프 뷰를 구축하고 있었습니다 — 비디오 세그먼트 간의 주제 체인과 의미 링크를 보여주는 React Flow 캔버스입니다. 노드는 정상적으로 렌더링되었지만, 뷰를 로드할 때마다 엣지(노드를 연결하는 선)가 그냥 사라졌습니다.

콘솔에는 오류가 없습니다. 노드는 제자리에 있습니다. 단지… 엣지가 없습니다.

아래는 이를 일으킨 두 가지 버그 체인입니다.

Bug 1: overflow‑hidden이 스태킹 컨텍스트를 생성해 SVG 가장자리를 클립함

첫 번째 원인은 이 래퍼였습니다:

// GraphView.tsx — BEFORE

  

overflow: hidden은 대부분의 사람들이 생각하지 못하는 두 가지 일을 합니다:

  1. 박스를 넘는 콘텐츠를 클립합니다 (명백한 효과).
  2. 새로운 스태킹 컨텍스트를 생성합니다.

React Flow는 엣지를 SVG 레이어로 렌더링하며, 이 레이어는 캔버스 컨테이너 안에 절대 위치합니다. 조상 요소에 overflow: hidden이 있으면, 그 SVG 레이어가 클립됩니다—보이는 범위 안에 technically 존재하더라도—왜냐하면 스태킹 컨텍스트가 브라우저가 레이어를 합성하는 방식을 바꾸기 때문입니다.

해결 방법

대신 overflow: clip을 사용합니다:

// GraphView.tsx — AFTER
{/* overflow‑clip instead of overflow‑hidden: clips visually without creating a new
    stacking context that would cause React Flow's SVG edge layer to be invisible */}

  

overflow: clip은 시각적으로 overflow: hidden과 동일하게 동작합니다—콘텐츠가 박스 경계에서 클립되지만—새로운 스태킹 컨텍스트를 생성하지는 않습니다. 이제 SVG 엣지 레이어가 올바르게 합성될 수 있습니다.

이것은 overflow: hidden이 복잡한 렌더링 시나리오(예: SVG 오버레이, 고정 위치 자식, 캔버스 기반 UI)에서 발생하는 불행한 부작용 때문에 특별히 존재하는 CSS 속성 중 하나입니다.

Source:

Bug 2: Next.js dynamic() imports need an explicit ReactFlowProvider

오버플로우 문제를 해결한 뒤에도 일부 경우에 엣지가 사라지는 현상이 있었습니다. 두 번째 버그는 좀 더 미묘했습니다.

React Flow는 내부적으로 React 컨텍스트를 사용합니다. <ReactFlow> 컴포넌트는 트리 어딘가에 ReactFlowProvider가 존재하기를 기대합니다. 대부분의 설정에서는 앱/페이지를 프로바이더로 감싸거나, React Flow 자체 내부 프로바이더가 컴포넌트가 렌더링되기 전에 초기화되도록 합니다.

문제점: 우리는 Next.js dynamic()을 사용해 그래프 컴포넌트를 로드하고 있었습니다.

// project/page.tsx
const VideoKnowledgeGraph = dynamic(
  () => import('@/components/VideoKnowledgeGraph'),
  { ssr: false }
);

dynamic()을 사용하면 컴포넌트가 별도 청크에서 비동기적으로 로드됩니다. 이때 React Flow 컨텍스트—특히 노드, 엣지 및 SVG 렌더러를 관리하는 내부 스토어를 담당하는 프로바이더—가 없거나 아직 초기화되지 않은 상태에서 SVG 엣지 레이어가 렌더링을 시도하게 됩니다.

결과: 노드는 렌더링되지만(내부 엣지 스토어에 동일하게 의존하지 않음), 엣지는 렌더링되지 않습니다.

Fix

동적으로 로드된 컴포넌트를 <ReactFlowProvider>로 명시적으로 감싸세요.

// VideoKnowledgeGraph.tsx — AFTER
import { ReactFlow, ReactFlowProvider, Background, Controls } from '@xyflow/react';

export default function VideoKnowledgeGraph({ graph, ...rest }) {
  // …
  return (
    // ReactFlowProvider는 이 컴포넌트가 Next.js dynamic() import로 로드되기 때문에 필요합니다.
    // 명시적인 프로바이더가 없으면 React Flow 컨텍스트(특히 SVG 엣지 렌더러)가 누락되어
    // 엣지가 렌더링되지 않을 수 있습니다.
    <ReactFlowProvider>
      <ReactFlow
        nodes={graph.nodes}
        edges={graph.edges}
        // …other props
      >
        <Background />
        <Controls />
        {/* toolbar */}
        {/* …other UI */}
      </ReactFlow>
    </ReactFlowProvider>
  );
}

Rule of thumb: dynamic()을 통해 로드되는 모든 React Flow 컴포넌트는 자체 ReactFlowProvider를 포함해야 합니다. 부모 컴포넌트에서 컨텍스트가 제공될 것이라고 가정하지 마세요—비동기 청크 로딩으로 초기화 순서가 불확실해집니다.

Source:

두 가지 버그가 모두 필요했던 이유

하나의 버그만 있어도 어느 정도는 동작했을 수 있습니다:

버그가능한 결과
스태킹 컨텍스트 문제만 존재일부 브라우저에서는 엣지가 표시되지만, 다른 브라우저에서는 잘려 보일 수 있음
프로바이더 누락만 존재상위에 프로바이더가 있다면 React Flow가 이를 사용해 fallback 할 수 있음

두 버그가 동시에 발생하면 다음과 같이 복합적인 문제가 생깁니다: SVG 레이어가 전혀 렌더링되지 않으며(프로바이더 문제), 설령 렌더링이 되더라도 overflow 문제로 잘려 보이게 됩니다.

React Flow에서 엣지 가시성을 디버깅할 때 먼저 확인할 두 가지 항목:

  1. 조상 요소에 overflow: hidden이 적용되어 있나요? overflow: clip 또는 overflow: visible로 변경하세요.
  2. 컴포넌트가 동적으로 로드되고 있나요? <ReactFlowProvider> 로 감싸 주세요.

Takeaway

overflow: hidden은 CSS의 “말보다 더 많은 일을 하는” 속성 중 하나로, 새로운 스태킹 컨텍스트를 생성해 SVG 오버레이, 고정 위치 자식 요소, 캔버스 기반 UI와 충돌할 수 있습니다. React Flow와 같이 엣지를 SVG 레이어에 렌더링하는 라이브러리를 사용할 때는, 스태킹 컨텍스트 효과가 명시적으로 필요하지 않다면 overflow: clip(또는 overflow: visible)을 사용하는 것이 좋습니다. 또한 Next.js dynamic()으로 컴포넌트를 비동기 로드할 때는 필요한 컨텍스트 프로바이더가 존재하는지 반드시 확인하세요.

t 생성. 그리고 React Flow를 Next.js dynamic()과 함께 사용할 때는 트리 상위에 컨텍스트가 존재한다고 기대하기보다 명시적으로 컨텍스트를 제공해야 합니다.

두 경우 모두 무엇을 찾아야 하는지 알면 한 줄 코드 수정으로 해결할 수 있습니다. 어려운 부분은 바로 그 “무엇을 찾아야 하는지”를 아는 것입니다.

0 조회
Back to Blog

관련 글

더 보기 »