변경 사항을 적용한 후 토픽 목록을 어떻게 업데이트할 수 있나요?

게시물(포스트) 작업 메뉴에 현재 주제 스레드에서 해당 게시물을 "분리(boots)"하는 커스텀 버튼을 구현했습니다. 이는 주제 작성자에게 제공되는 작업으로, 기본적으로 이동(move) 작업을 수행하지만 클릭 횟수를 줄인 것입니다. 백엔드 작업은 새로운 커스텀 API 엔드포인트를 통해 처리됩니다. 버튼은 정상적으로 작동하지만, 게시물이 이동되었음을 확인하려면 수동으로 페이지를 새로고침해야 합니다.

새로고침 후 게시물은 다음과 같이 표시됩니다:

질문은 이 변경 사항을 DOM에 업데이트하는 가장 좋은 방법이 무엇인지입니다. 이상적으로는 위 이미지와 같은 분할(split) 플레이스홀더로 게시물을 교체하고, 전체 페이지나 전체 주제 목록을 새로고침하는 것을 피하는 것입니다.

API 엔드포인트에서 변경된 주제를 반환하도록 하면, 주제 목록에 새 게시물을 교체/주입하기만 하면 된다고 생각할 수 있습니다.

따라서 이는 Discourse 내부의 상태 관리(state management)가 어떻게 작동하는지, 그리고 제가 그 라이프사이클에 어떻게 연결(hook)할 수 있는지에 대한 질문인 것 같습니다.

MessageBus를 업데이트하는 항목을 core(또는 all-the-plugins 저장소)에서 찾아보세요.

해결책

API 메서드 끝에 다음 코드를 추가하는 것으로 문제를 해결했습니다:

MessageBus.publish("/topic/#{@topic.id}", reload_topic: true, refresh_stream: true)

이렇게 하면 현재 사용자에게만 아니라 해당 토픽을 보고 있는 다른 모든 사용자에게도 새로고침이 이루어져야 합니다.

여기까지 도달하게 된 탐색 과정

코드베이스를 따라 함께 보고 싶다면 아래를 읽어보세요. 다른 분들에게도 유용할 수 있어 공유합니다.

MessageBus란?

Sam의 2013년 MessageBus 설명에 따르면 Ruby 코드는 게시(publish)와 구독(subscribe)을 할 수 있는 반면, Javascript 코드는 구독만 할 수 있는 것 같습니다. 즉, 제안된 아키텍처에 따르면 서버 측 코드가 UI를 알리는 역할을 담당하게 됩니다.

저에게 유용한 MessageBus 예시가 있나요?

플러그인 예시 중 MessageBus를 사용하는 것은 없습니다.

GroupArchivedMessage.move_to_inbox!은 제가 원하는 것과 다소 유사한 이 코드를 호출하지만, 여기서 사용되는 type 코드는 제 경우에 사용할 수 없습니다.

MessageBus.publish("/topic/#{topic_id}", { type: "move_to_inbox" }, group_ids: [group_id])

이 코드는 유망해 보입니다.

MessageBus.publish("/topic/#{@topic.id}", reload_topic: true, refresh_stream: true)

제가 최종적으로 선택한 해결책입니다.

브라우저가 업데이트를 수신하면 어떻게 되나요?

Topics 컨트롤러는 현재 보고 있는 토픽의 업데이트를 구독합니다. 이는 "post-stream:refresh"를 트리거하여 새로고침을 시작합니다. 다른 끝에서 이 이벤트를 수신하는 것으로 찾을 수 있는 것은 ScrollingPostStream뿐이며, 이는 _refresh 메서드를 이벤트에 바인딩합니다. 이것이 실제로 업데이트를 수행하는 것으로 보입니다.

이로부터, 다른 사용자에게 업데이트를 푸시하지 않고 현재 클라이언트만 업데이트하려면 동일한 코드를 직접 호출할 수 있다고 추론할 수 있습니다:

this.appEvents.trigger("post-stream:refresh", args)

그리고 이는 어떤 컴포넌트에서든 호출할 수 있는 것으로 보입니다.

move_posts의 원래 구현은 어떻게 되나요? MessageBus에 게시하나요?

코어 코드를 조사해 보니: 토픽 컨트롤러의 move_posts() 메서드는 move_posts_to_destination()를 호출하고, 이는 topic.move_posts()를 호출하며, 이는 new PostMover()를 호출한 후 to_topic() 또는 to_new_topic()를 호출합니다. 이 메서드들은 MessageBus를 호출하지 않지만 DiscourseEvent.trigger()는 호출합니다.

저는 커스텀 API 메서드에서 topic.move_posts()를 호출합니다. 즉, 제 코드는 컨트롤러 로직을 건너뛰고 모델로 직접 호출합니다:

new_topic = topic.move_posts(current_user, [post.id], {title: title, category_id: category_id})

제 경우, 시퀀스의 마지막 단계로 move_posts_to()가 호출되며, 이는 다음을 호출합니다:

DiscourseEvent.trigger(
  :posts_moved,
  destination_topic_id: destination_topic.id,
  original_topic_id: original_topic.id,
)

그러나 DiscourseEvent는 MessageBus와 아무 관련이 없는 것 같습니다. 서버 내부의 라이프사이클에만 사용되는 걸까요?

따라서 토픽 이동 시 MessageBus에 게시되지 않는다고 결론 내립니다.

아, 죄송합니다. 조금 놀랍네요! 아마도 core 쪽으로 안내를 드렸어야 했을 것 같습니다. 제가 MessageBus를 사용하는 플러그인이 하나 있지만, 공개되어 있지 않으며 커스텀 모델에 MessageBus를 사용하고 있습니다.

확신은 없지만, reload topic이 필요하지 않을 것 같습니다(변경된 속성 없이 표시되지 않는 정보가 변경되는 경우가 아니라면요). 하지만 제 플러그인에서는 reload topic이 문제를 해결해 줄 수 있을 것 같은 곳이 몇 군데 있습니다!