Как использовать Rails и Hotwire Turbo Streaming для потоковой передачи длинной страницы?

Я посмотрел https://turbo.hotwired.dev/handbook/streams и https://www.hotrails.dev/turbo-rails/turbo-streams , но не понял, как это сделать. .

У меня длинная страница с множеством сообщений. Когда страница загружается, она должна передавать сообщения. Предположим, имеется 100 сообщений, и обработка каждого сообщения занимает 100 мс. Пользователь должен видеть одно сообщение каждые 100 мс, чтобы они отображались по мере потоковой передачи.

На индексной странице будет целевой идентификатор:

<div id = "messages"></div>

Кажется, будет частичное сообщение:

<turbo-stream action = "append" target = "messages">
  <template>
    <turbo-frame id = "message">
      <%= message.text %>
    </turbo-frame>
  </template>
</turbo-stream>

Кажется, что контроллер может выглядеть так:

@messages = Message.last(100)

respond_to do |format|
  format.html do
  end

  format.turbo_stream do
    render turbo_stream: turbo_stream.append(:messages, partial: 'message',
      locals: { collection: @messages })
  end
end

Не уверен, будет ли транслироваться вся страница или только сообщения.

Если вся страница транслируется, то, как я понимаю, вам нужно заставить Rails визуализировать турбо_поток без запроса потоковой передачи. Но не знаю, как нацелиться на рамку _top.

Если передаются только сообщения, то, похоже, нам нужен механизм для запуска потоковой передачи при рендеринге индексной страницы. Не уверен, есть ли для этого команда JS Turbo...

Пожалуйста, не говорите мне, что это неправильно. Я знаю, что передавать много сообщений в потоковом режиме — плохая идея. Это упрощенный пример варианта использования. Этот упрощенный пример облегчает понимание без добавления дополнительного контекста.

Обновлено: Рельсы 7.1.2.

Вы не делаете что-то неправильное, но вы думаете об этом неправильно. Вся идея декомпозиции состоит в том, чтобы создать впечатление, что страница загружается быстрее, поскольку пользователь может быстрее взаимодействовать со страницей, даже если на самом деле в целом требуется больше времени, прежде чем все будет загружено и отображено. Чего я не понимаю, так это почему вы думаете, что вам следует ориентироваться на фрейм _top, поскольку это приведет к повторному рендерингу всей страницы.

max 03.06.2024 13:13
Стоит ли изучать PHP в 2026-2027 годах?
Стоит ли изучать PHP в 2026-2027 годах?
Привет всем, сегодня я хочу высказать свои соображения по поводу вопроса, который я уже много раз получал в своем сообществе: "Стоит ли изучать PHP в...
Поведение ключевого слова "this" в стрелочной функции в сравнении с нормальной функцией
Поведение ключевого слова "this" в стрелочной функции в сравнении с нормальной функцией
В JavaScript одним из самых запутанных понятий является поведение ключевого слова "this" в стрелочной и обычной функциях.
Приемы CSS-макетирования - floats и Flexbox
Приемы CSS-макетирования - floats и Flexbox
Здравствуйте, друзья-студенты! Готовы совершенствовать свои навыки веб-дизайна? Сегодня в нашем путешествии мы рассмотрим приемы CSS-верстки - в...
Тестирование функциональных ngrx-эффектов в Angular 16 с помощью Jest
В системе управления состояниями ngrx, совместимой с Angular 16, появились функциональные эффекты. Это здорово и делает код определенно легче для...
Концепция локализации и ее применение в приложениях React ⚡️
Концепция локализации и ее применение в приложениях React ⚡️
Локализация - это процесс адаптации приложения к различным языкам и культурным требованиям. Это позволяет пользователям получить опыт, соответствующий...
Пользовательский скаляр GraphQL
Пользовательский скаляр GraphQL
Листовые узлы системы типов GraphQL называются скалярами. Достигнув скалярного типа, невозможно спуститься дальше по иерархии типов. Скалярный тип...
1
1
116
2
Перейти к ответу Данный вопрос помечен как решенный

Ответы 2

Ответ принят как подходящий

Обратите внимание, что турбопоток сам по себе не является потоковым ответом, это обычный http/html. Вы можете создать свой собственный Турбо-канал и транслировать с него:

# app/channels/messages_channel.rb

class MessagesChannel < Turbo::StreamsChannel
  def subscribed
    super

    Message.last(100).each do |message|
      MessagesChannel.broadcast_append_to(
        verified_stream_name_from_params,
        target: "messages",
        partial: "messages/message",
        locals: {message:}
      )
    end
  end
end
# app/views/messages/_message.html.erb

<%= tag.div id: dom_id(message) do %>
  <%= message.text %>
<% end %>

В вашем шаблоне:

<%= turbo_stream_from "messages", channel: "MessagesChannel" %>

<div id = "messages"></div>
turbo stream is not a streaming response - Я это понял после публикации. Я так понимаю, каждое сообщение будет транслироваться индивидуально, так что это тоже сработает.
B Seven 03.06.2024 20:06

В проекте приложения для социальных сетей для портфолио я реализовал подход для бесконечной прокрутки сообщений на временной шкале и страницах профиля с использованием Turboframes и Turbo Streams.

Во-первых, давайте лениво загрузим посты с контроллера в турбо-формате. Я также использую драгоценный камень will-paginate для нумерации страниц. Логика здесь заключается во втором теге турбо-фрейма, где мы снова лениво загружаем сообщения, если у нас остались какие-либо сообщения (на следующей странице). Отложенная загрузка происходит только тогда, когда этот компонент становится видимым на экране.

<%# app/views/timeline/index.html.erb %>
      <%= turbo_frame_tag "posts", src: root_path(format: :turbo_stream), loading: :lazy %>
      <% if @posts.next_page %>
        <%= turbo_frame_tag "load_more", src: root_path(page: @posts.next_page, format: :turbo_stream), loading: :lazy %>
      <% end %>
    </div>
    <div class = "mt-8">
      <p class = "text-gray-500">🚀 Current page: <span id = "current_page"><%= @posts.current_page %></span></p>
    </div> 

Итак, когда мы получаем ответ турбопотока, мы добавляем сообщение к сообщениям и заменяем турбокадр load_more следующей страницей в качестве параметра, поэтому, когда пользователь прокручивает дальше вниз и этот load_more становится видимым, он загружает больше сообщений и процесс повторяется.

<%# app/views/timeline/index.turb_stream.erb %>
<%= turbo_stream.append "posts" do %>
  <%= render partial: "posts/post", collection: @posts %>
<% end %>
<% if @posts.next_page %>
  <%= turbo_stream.replace "load_more" do %>
    <%= turbo_frame_tag "load_more", src: root_path(page: @posts.next_page, format: :turbo_stream), loading: :lazy %>
  <% end %>
<% end %>
<%= turbo_stream.update "current_page", @posts.current_page %>

На стороне контроллера мы просто загружаем сообщения с нумерацией страниц и параметром страницы.

class HomeController < ApplicationController
  def index
    friend_ids = current_user.friends.pluck(:id)
    friend_ids << current_user.id
    # @posts = Post.paginate(page: params[:page], per_page: 1).order('created_at DESC')
    @posts = Post.where(user_id: friend_ids).paginate(page: params[:page], per_page: 1).order('created_at DESC')
  end
end

Таким образом, мы можем загружать огромные объемы данных на страницу с отложенной загрузкой и бесконечной прокруткой без какой-либо строки кода JavaScript.

Другие вопросы по теме

Похожие вопросы