質問をすることでしか得られない、回答やアドバイスがある。

15分調べてもわからないことは、質問しよう!

新規登録して質問してみよう
ただいま回答率
85.47%
Laravel

LaravelとはTaylor Otwellによって開発された、オープンソースなPHPフレームワークです。Laravelはシンプルで表現的なシンタックスを持ち合わせており、ウェブアプリケーション開発の手助けをしてくれます。

PHP

PHPは、Webサイト構築に特化して開発されたプログラミング言語です。大きな特徴のひとつは、HTMLに直接プログラムを埋め込むことができるという点です。PHPを用いることで、HTMLを動的コンテンツとして出力できます。HTMLがそのままブラウザに表示されるのに対し、PHPプログラムはサーバ側で実行された結果がブラウザに表示されるため、PHPスクリプトは「サーバサイドスクリプト」と呼ばれています。

非同期処理

非同期処理とは一部のコードを別々のスレッドで実行させる手法です。アプリケーションのパフォーマンスを向上させる目的でこの手法を用います。

Docker

Dockerは、Docker社が開発したオープンソースのコンテナー管理ソフトウェアの1つです

React.js

Reactは、アプリケーションのインターフェースを構築するためのオープンソースJavaScriptライブラリです。

Q&A

4回答

442閲覧

音声配信プラットフォームを作ろうとしていますが、コメントがリアルタイムに反映されません。

reborn8907

総合スコア0

Laravel

LaravelとはTaylor Otwellによって開発された、オープンソースなPHPフレームワークです。Laravelはシンプルで表現的なシンタックスを持ち合わせており、ウェブアプリケーション開発の手助けをしてくれます。

PHP

PHPは、Webサイト構築に特化して開発されたプログラミング言語です。大きな特徴のひとつは、HTMLに直接プログラムを埋め込むことができるという点です。PHPを用いることで、HTMLを動的コンテンツとして出力できます。HTMLがそのままブラウザに表示されるのに対し、PHPプログラムはサーバ側で実行された結果がブラウザに表示されるため、PHPスクリプトは「サーバサイドスクリプト」と呼ばれています。

非同期処理

非同期処理とは一部のコードを別々のスレッドで実行させる手法です。アプリケーションのパフォーマンスを向上させる目的でこの手法を用います。

Docker

Dockerは、Docker社が開発したオープンソースのコンテナー管理ソフトウェアの1つです

React.js

Reactは、アプリケーションのインターフェースを構築するためのオープンソースJavaScriptライブラリです。

0グッド

0クリップ

投稿2024/02/17 13:50

実現したいこと

ReactとLaravelやっている人がいたら相談したいことがあります・・・。
現在Youtubeの配信のコメント欄のようにリアルタイムでコメントが流れるような機能を作ろうとしています。
それでPusherというSaasを用いてWebSocket通信をしてリアルタイムコメントを実装しようと思っています。

ただ、片方のタブで送信したコメントを、もう片方のタブで開いた時に一度再読み込みをしないと反映されません。
映像のように、Command+Rで再読み込みをしなければ反映されません。

発生している問題・エラーメッセージ

エラーメッセージ

該当のソースコード

ルーティング

api.php

1<?php 2 3use Illuminate\Http\Request; 4use Illuminate\Support\Facades\Route; 5use App\Http\Controllers\CommentController; 6/* 7|-------------------------------------------------------------------------- 8| API Routes 9|-------------------------------------------------------------------------- 10| 11| Here is where you can register API routes for your application. These 12| routes are loaded by the RouteServiceProvider and all of them will 13| be assigned to the "api" middleware group. Make something great! 14| 15*/ 16 17Route::middleware('auth:sanctum')->get('/user', function (Request $request) { 18 return $request->user(); 19}); 20 21// 既存のコメント取得エンドポイント 22Route::get('/comments', [CommentController::class, 'index'])->name('get.broadcastingRooms.comment'); 23 24// 新しいコメント作成エンドポイント 25Route::post('/comments', [CommentController::class, 'store'])->name('store.broadcastingRooms.comment'); 26

CommentController.php

1<?php 2 3namespace App\Http\Controllers; 4 5use App\Events\SentComment; 6use App\Models\Comment; 7use Illuminate\Http\Request; 8use Illuminate\Support\Facades\Event; 9use Illuminate\Support\Facades\Log; 10class CommentController extends Controller 11{ 12 public function index(Request $request) 13 { 14 $comments = Comment::all(); 15 event(new SentComment($comments)); 16 return response()->json($comments); 17 } 18 19 public function store(Request $request) 20 { 21 $this->validate($request, [ 22 'text' => 'required', 23 ]); 24 $commentModel = new Comment(); 25 $comment = $commentModel->insertComment($request); 26 event(new SentComment($comment)); 27 return response()->json(); 28 } 29} 30

Comment.php

1<?php 2namespace App\Models; 3 4use Illuminate\Database\Eloquent\Factories\HasFactory; 5use Illuminate\Database\Eloquent\Model; 6use Illuminate\Database\Eloquent\Relations\BelongsTo; 7use Illuminate\Support\Facades\Log; 8 9class Comment extends Model 10{ 11 use HasFactory; 12 13 protected $fillable = ['comment']; // フィールド名を修正 14 protected $table = 'broadcasting_rooms_comments'; 15 16 public function broadcastingRoom(): BelongsTo 17 { 18 return $this->belongsTo(BroadcastingRoom::class); 19 } 20 21 public function insertComment($request) 22 { 23 $requestBody = file_get_contents('php://input'); 24 25 // JSON文字列を連想配列に変換 26 $jsonData = json_decode($requestBody, true); 27 28 // "text" フィールドの値を取得 29 $commentText = $jsonData['text']; 30 $comment = new Comment(); 31 $referer = $request->headers->get('referer'); // リクエストの Referer を取得 32 //refererが配信者・視聴者のどちらかのURLかを判定 33 if (strpos($referer, "http://localhost/broadcast/") !== false) { 34 //視聴者の場合 35 if(strpos($referer, "http://localhost/broadcast/stream") !== false) { 36 $pattern = "http://localhost/broadcast/stream/"; 37 $broadcastId = str_replace($pattern, "", $referer); 38 $comment->broadcasting_rooms_id = $request->input('broadcasting_rooms_id', (int)$broadcastId); 39 $comment->comment = $request->input('comment', $commentText); 40 $comment->save(); 41 return $comment; 42 //配信者の場合 43 } else { 44 $pattern = "http://localhost/broadcast/"; 45 $broadcastId = str_replace($pattern, "", $referer); 46 $comment->broadcasting_rooms_id = $request->input('broadcasting_rooms_id', (int)$broadcastId); 47 $comment->comment = $request->input('comment', $commentText); 48 $comment->save(); 49 return $comment; 50 } 51 } 52 } 53} 54

下記が配信者用の画面です

BroadcastRoom.jsx

1import React, { useEffect, useState } from 'react'; 2import FileTree from './FolderTree/FileTree'; 3import Editor from './Editor'; 4import CommentForm from './Comment/CommentForm'; 5import CommentList from './Comment/CommentList'; 6import AudioStreamer from './Audio/AudioStreamer'; 7 8const BroadcastRoom = () => { 9 const [fileNames, setFileNames] = useState([]); 10 const [comments, setComments] = useState([]); 11 12 useEffect(() => { 13 // URLのパラメーターを使用してAPIからデータを取得するなどの処理をここに記述 14 fetch('/api/comments') 15 .then((response) => response.json()) 16 .then((data) => { 17 setComments(data); 18 }); 19 20 // Pusherを使ったリアルタイムコメントのリッスンを追加 21 window.Echo.channel('comment') 22 .listen('.SentComment', (e) => { 23 setComments(prevComments => [...prevComments, e.comment]); 24 }); 25 }, []); 26 27 const addComment = (newComment) => { 28 // 新しいコメントオブジェクトにIDを追加する 29 const commentWithId = { ...newComment }; 30 31 fetch('/api/comments', { 32 method: 'POST', 33 headers: { 34 'Content-Type': 'application/json', 35 }, 36 // IDを含めたコメントオブジェクトをJSON文字列に変換してリクエストのボディに設定する 37 body: JSON.stringify(commentWithId), 38 }) 39 .then((response) => response.json()) 40 .then((data) => { 41 setComments([...comments, data]); 42 fetch('/api/comments') 43 .then((response) => response.json()) 44 .then((data) => setComments(data)); 45 }); 46 }; 47 48 return ( 49 <div className='all-space'> 50 <AudioStreamer /> 51 <div style={{ display: 'flex' }}> 52 <FileTree fileNames={ fileNames } setFileNames={ setFileNames } /> 53 <div style={{ flex: 1 }}> 54 <Editor selectedFiles={ fileNames } /> 55 </div> 56 <div className='comments'> 57 <CommentList comments={ comments } updateComments={ setComments } /> 58 <CommentForm onAddComment={ addComment } /> 59 </div> 60 </div> 61 </div> 62 ); 63}; 64 65export default BroadcastRoom; 66

ViewerDashboard.jsx

1import React, { useEffect, useState} from 'react'; 2import CommentForm from './Comment/CommentForm'; 3import CommentList from './Comment/CommentList'; 4 5const ViewerDashboard = () => { 6 const [comments, setComments] = useState([]); 7 8 useEffect(() => { 9 fetch('/api/comments') 10 .then((response) => response.json()) 11 .then((data) => setComments(data)); 12 13 // Pusherを使ったリアルタイムコメントのリッスンを追加 14 window.Echo.channel('comment') 15 .listen('.SentComment', (e) => { 16 setComments(prevComments => [...prevComments, e.comment]); 17 }); 18 }, []); 19 20 const addComment = (newComment) => { 21 fetch('/api/comments', { 22 method: 'POST', 23 headers: { 24 'Content-Type': 'application/json', 25 }, 26 body: JSON.stringify(newComment), 27 }) 28 .then((response) => response.json()) 29 .then((data) => { 30 setComments([...comments, data]); 31 fetch('/api/comments') // GETリクエストを実行してコメント一覧を更新 32 .then((response) => response.json()) 33 .then((data) => setComments(data)); 34 }); 35 }; 36 37 return ( 38 <div> 39 <h1>視聴者用の画面</h1> 40 <CommentList comments={ comments } updateComments={ setComments } /> 41 <CommentForm onAddComment={ addComment } /> 42 </div> 43 ); 44}; 45 46export default ViewerDashboard; 47

下記がイベントです。

SentComment.php

1<?php 2namespace App\Events; 3use Illuminate\Support\Facades\Log; 4use Illuminate\Broadcasting\Channel; 5use Illuminate\Broadcasting\InteractsWithSockets; 6use Illuminate\Contracts\Broadcasting\ShouldBroadcast; 7use Illuminate\Foundation\Events\Dispatchable; 8use Illuminate\Queue\SerializesModels; 9 10class SentComment implements ShouldBroadcast 11{ 12 use Dispatchable, InteractsWithSockets, SerializesModels; 13 14 /** 15 * The new comment. 16 * 17 * @var \App\Models\Comment 18 */ 19 public $comment; 20 21 /** 22 * Create a new event instance. 23 * 24 * @param \App\Models\Comment $comment 25 */ 26 27 public function __construct($comment) 28 { 29 $this->comment = $comment; 30 } 31 32 /** 33 * Get the channels the event should broadcast on. 34 * 35 * @return array<int, \Illuminate\Broadcasting\Channel> 36 */ 37 38 public function broadcastOn(): array 39 { 40 return [new Channel('comment')]; 41 42 } 43} 44

bootstrap.js

1/** 2 * We'll load the axios HTTP library which allows us to easily issue requests 3 * to our Laravel back-end. This library automatically handles sending the 4 * CSRF token as a header based on the value of the "XSRF" token cookie. 5 */ 6 7/** 8 * Echo exposes an expressive API for subscribing to channels and listening 9 * for events that are broadcast by Laravel. Echo and event broadcasting 10 * allows your team to easily build robust real-time web applications. 11 */ 12 13 import Echo from 'laravel-echo'; 14 15 import Pusher from 'pusher-js'; 16 window.Pusher = Pusher; 17 18 window.Echo = new Echo({ 19 broadcaster: 'pusher', 20 key: import.meta.env.VITE_PUSHER_APP_KEY, 21 cluster: import.meta.env.VITE_PUSHER_APP_CLUSTER ?? 'mt1', 22 wsHost: import.meta.env.VITE_PUSHER_HOST ? import.meta.env.VITE_PUSHER_HOST : `ws-${import.meta.env.VITE_PUSHER_APP_CLUSTER}.pusher.com`, 23 wsPort: import.meta.env.VITE_PUSHER_PORT ?? 80, 24 wssPort: import.meta.env.VITE_PUSHER_PORT ?? 443, 25 forceTLS: (import.meta.env.VITE_PUSHER_SCHEME ?? 'https') === 'https', 26 enabledTransports: ['ws', 'wss'], 27 }); 28

試したこと

Pusherのデバッグ用のログを確認しました。
2つのViewを別のタブで開いている状態で、Subscriptionのログがあるのかを見てみたのですが、片方の画面でコメントが反映されたとしてももう片方の画面ではリロードしなければSubscriptionの処理がされません。
公式ドキュメントのやり方でbootstrap.jsのコメントアウトを外すというのは見てやってみたのですができませんでした。

環境

Laravel10
laravel-sail
React.js(Laravelに付属しているReactです。別のReactアプリケーションとして立ち上げているわけではありません。同じコンテナ内で動いています。)

よろしくお願いいたします。

気になる質問をクリップする

クリップした質問は、後からいつでもMYページで確認できます。

またクリップした質問に回答があった際、通知やメールを受け取ることができます。

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

guest

回答4

0

アプリケーションがデータベースを使用してユーザーからの応答を保存する場合は、データベースが一度に多数の要求を処理できるように最適化されていることを確認してください。 fnf

投稿2024/03/29 02:23

maicleusa

総合スコア6

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

0

実際、これらのプログラムを実行するには、それぞれ特定の式とシーケンスが必要です。 新しい標準の確立と構築が容易になります。 継続的な学習に役立つ情報 geometry dash lite

投稿2024/02/27 09:52

thinignoramus

総合スコア2

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

0

解決はしましたが、良い解決策とは思えないです。
ただ、一応共有はします。

Pusherはログを吐き出させると、そのチャンネルの情報をリアルタイムに共有してくれます。
今回の場合はコメントです。
どういったコメントがあるのかという内容のログをリアルタイムで吐き出してくれます。
なので、それを読み取れば良いということになります。

コードは下記です。

AllBroadcasting.jsx

1const usePusherComments = () => { 2 const [pusherComments, setComments] = useState([]); 3 4 Pusher.log = function(message) { 5 //Event recdという名前のログを吐くのでそれをキャッチ 6 const startIndex = message.indexOf('"Event recd"'); 7 if (startIndex !== -1) { 8 const jsonStartIndex = message.indexOf('{', startIndex); 9 if (jsonStartIndex !== -1) { 10 const jsonString = message.substring(jsonStartIndex); 11 const jsonEndIndex = jsonString.lastIndexOf('}'); 12 const json = jsonString.substring(0, jsonEndIndex + 1); 13 try { 14 const eventData = JSON.parse(json); 15 if (eventData.data && eventData.data.comment) { 16 const comments = eventData.data.comment; 17 setComments(comments); 18 } 19 } catch (error) { 20 console.error('Error parsing JSON:', error); 21 } 22 } 23 } 24 }; 25 26 return pusherComments; 27}; 28

新しくコンポーネントを宣言して、ログの中のコメントを格納しているオブジェクトをキャッチしてそれを変数に格納させて返すようにしました。
ただあまりいい解決策とは言えないと思うので、何かありましたら共有してもらえると助かります。

ありがとうございました。

投稿2024/02/22 12:14

reborn8907

総合スコア0

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

0

ReactもPusherもやったことないんでよくわかんないですけど、多分コメントを送信したときにそれを他の利用者にWebSocketで送るような処理が入ってないんじゃないですかね。

jsのaddComment 内で、コメントを入力して送信したときに、コメントをサーバーに保存するためにfetchでpostしてますが、それと同時にWebSocketでも送ってやらないといけないですね。

送信が正常に行われているかは、ブラウザの開発者ツールのネットワークタブで確認できます。

投稿2024/02/17 23:43

otftrough

総合スコア476

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

reborn8907

2024/02/18 02:37

なるほど。 試してみます!!! ありがとうございます!!!
reborn8907

2024/02/18 03:22

ソケット通信はできています。 ただ、CommentListコンポーネントというコメントをリストで表示する箇所にわたっていないだけのようです。 なのでそこを修正してみます。
guest

あなたの回答

tips

太字

斜体

打ち消し線

見出し

引用テキストの挿入

コードの挿入

リンクの挿入

リストの挿入

番号リストの挿入

表の挿入

水平線の挿入

プレビュー

まだベストアンサーが選ばれていません

会員登録して回答してみよう

アカウントをお持ちの方は

15分調べてもわからないことは
teratailで質問しよう!

ただいまの回答率
85.47%

質問をまとめることで
思考を整理して素早く解決

テンプレート機能で
簡単に質問をまとめる

質問する

関連した質問