Hotwire 앱에서 자체 업데이트 컴포넌트 구현 전략

Hotwire components that refresh themselves | Boring Rails: Skip the bullshit and ship fast

작성자
발행일
2025년 07월 07일

핵심 요약

  • 1 Hotwire 기반 애플리케이션에서 UI 업데이트 시 발생하는 파셜 및 식별자 관리의 복잡성을 개선하는 패턴을 제시합니다.
  • 2 ViewComponent를 활용하여 컴포넌트가 자체적으로 UI 갱신 로직을 포함하도록 하여 코드의 응집도를 높이는 방법을 소개합니다.
  • 3 컴포넌트 내부에 `dom_id`와 ActionCable 브로드캐스트 채널을 캡슐화하여 유지보수성과 재사용성을 향상시킵니다.

도입

Hotwire 기반의 Ruby on Rails 애플리케이션에서 동적인 UI를 구현할 때, `turbo_streams`와 파셜(partials)을 사용하는 것이 일반적입니다. 그러나 이 방식은 UI 요소의 `dom_id`를 여러 파일에 분산시키고, 데이터 전달을 위한 `locals` 사용을 강제하며, 코드베이스 내에서 파셜의 사용처를 추적하기 어렵게 만드는 등 여러 가지 비효율성을 야기합니다. 이로 인해 컴포넌트의 식별자가 변경될 경우, 관련 코드를 수동으로 모두 찾아 업데이트해야 하는 번거로움이 발생하며, 이는 대규모 애플리케이션에서 특히 유지보수성 문제를 심화시킵니다. 본 글은 이러한 '엉킨 식별자' 문제를 해결하고, 컴포넌트가 자체적으로 UI를 갱신할 수 있도록 하는 효과적인 패턴을 제안합니다.

기존의 turbo_streams 방식은 백그라운드 작업이나 모델에서 Turbo::StreamsChannel.broadcast_replace_to와 같은 메서드를 사용하여 특정 target ID를 가진 HTML 요소를 파셜로 교체하는 방식으로 작동합니다. 이때 target ID는 파셜 내의 HTML 요소 ID와 일치해야 하며, 이는 ActionView::RecordIdentifier.dom_id와 같은 헬퍼를 사용하더라도 여전히 여러 곳에 동일한 식별자가 분산되는 문제를 발생시킵니다. 이는 컴포넌트의 ID가 변경될 때마다 참조하는 모든 코드를 수정해야 하는 번거로움으로 이어집니다.

이러한 문제를 해결하기 위해 저자는 ViewComponent(또는 Phlex와 같은 유사 라이브러리)의 활용을 제안합니다. ViewComponent를 사용하면 뷰 로직뿐만 아니라 관련된 헬퍼, 심지어는 UI 갱신 로직까지 하나의 Ruby 클래스 내에 캡슐화할 수 있습니다. 예를 들어, UI::UserCard와 같은 컴포넌트 클래스 내에 id 메서드를 정의하여 dom_id를 중앙 집중화하고, broadcast_channel 메서드를 통해 ActionCable 채널 정보를 관리할 수 있습니다. 더 나아가, broadcast_refresh!와 같은 메서드를 컴포넌트 내부에 구현하여 해당 컴포넌트가 언제든지 자신을 갱신하도록 할 수 있습니다. 이 broadcast_refresh! 메서드는 Turbo::StreamsChannel.broadcast_replace_to를 호출할 때 renderable: self 옵션을 사용하여 컴포넌트 객체 자체를 렌더링하도록 지시함으로써, 파셜과 locals를 명시적으로 전달할 필요 없이 컴포넌트가 스스로를 갱신할 수 있게 합니다.

이러한 접근 방식은 컨트롤러에서도 유용하게 활용됩니다. 예를 들어, 사용자가 버튼을 클릭하여 이메일 전송과 같은 비동기 작업을 시작할 때, 컨트롤러는 즉시 turbo_stream.replace를 통해 컴포넌트의 ‘전송 중’ 상태를 반영하는 새 버전을 렌더링할 수 있습니다. 백그라운드 작업이 완료되면, 해당 작업 내에서 다시 broadcast_refresh!를 호출하여 컴포넌트의 최종 상태(예: 이메일 전송 완료)를 반영하도록 합니다.

또한, 컴포넌트의 상태(예: sending_email?)를 활용하여 필요한 경우에만 ActionCable 스트림을 열고 닫는 조건부 스트리밍을 구현할 수 있습니다. 이는 불필요하게 스트림을 열어두는 것을 방지하여 리소스 효율성을 높입니다. 예를 들어, 이메일 전송 중일 때만 스트림을 구독하고, 전송이 완료되면 구독을 해제하도록 하여 UI 업데이트의 라이프사이클을 더욱 정교하게 제어할 수 있습니다.

결론

ViewComponent와 같은 도구를 활용하여 UI의 특정 부분을 비즈니스 로직과 함께 컴포넌트 내에 캡슐화하는 것은 Hotwire 애플리케이션 개발에 있어 큰 이점을 제공합니다. 이 접근 방식은 로직을 응집시키고, UI가 변경될 때 명확한 갱신 방법을 제시하며, `dom_id`나 브로드캐스트 채널과 같은 핵심 식별자를 한 곳에 집중시켜 향후 리팩토링을 훨씬 용이하게 만듭니다. '관심사의 분리(Separation of Concerns)'라는 엄격한 원칙을 따르는 대신, '행동의 지역성(locality of behavior)'을 중시함으로써 코드베이스를 훨씬 더 다루기 쉽고 이해하기 쉽게 만들 수 있습니다. 이는 개발 생산성 향상 및 유지보수 비용 절감에 기여하는 효과적인 개발 패턴입니다.

댓글 0

댓글 작성

0/1000
정중하고 건설적인 댓글을 작성해 주세요.

아직 댓글이 없습니다

첫 번째 댓글을 작성해보세요!