リアルタイムチャットコンポーネントの構築
WebSocket eventsとReact stateを使い、スクロール可能なチャットリストにリアルタイムのメッセージを表示します。
「リアルタイムチャットコンポーネントの構築」はCoddyKit上の無料React Academyレッスンです。 これはレッスン3/4です。 下記で完全なレッスンを無料で読むことができます。その後、ブラウザ内の組み込みコードエディタと24時間対応のAIチューターでハンズオン演習できます。 これはReact Academy学習パスの一部であり、ウェブとCoddyKitアプリ全体で進捗が同期されます。 React Academyコースには全4レッスンが含まれています。
チャットコンポーネントのアーキテクチャ
リアルタイムチャットは、メッセージ一覧(表示)、メッセージ入力(送信)、WebSocket/Socket.IO 接続レイヤーの 3 つで構成されます。ソケットのロジックはカスタムフックにまとめてください。
メッセージデータの形
チャットメッセージ用の TypeScript インターフェースを定義すると、コンポーネント全体で型安全性を保てます。
interface Message {
id: string;
text: string;
sender: string;
timestamp: number;
}
const [messages, setMessages] = useState<Message[]>([]);useChat フック
接続、メッセージの状態、送信関数を 1 つのフックにまとめます。
function useChat(roomId: string) {
const [messages, setMessages] = useState<Message[]>([]);
useEffect(() => {
socket.connect();
socket.emit('join-room', roomId);
socket.on('message', (msg: Message) => setMessages(m => [...m, msg]));
return () => {
socket.off('message');
socket.emit('leave-room', roomId);
socket.disconnect();
};
}, [roomId]);
const sendMessage = useCallback((text: string) => {
const msg: Message = { id: crypto.randomUUID(), text, sender: 'me', timestamp: Date.now() };
socket.emit('message', msg);
}, []);
return { messages, sendMessage };
}メッセージ一覧コンポーネント
メッセージをスクロール可能な一覧に表示します。末尾の sentinel に useRef を使用し、新しいメッセージが届いたときにそこまでスクロールします。
function MessageList({ messages }: { messages: Message[] }) {
const bottomRef = useRef<HTMLDivElement>(null);
useEffect(() => {
bottomRef.current?.scrollIntoView({ behavior: 'smooth' });
}, [messages]);
return (
<div className="message-list">
{messages.map(msg => (
<div key={msg.id} className={`msg ${msg.sender === 'me' ? 'mine' : 'theirs'}`}>
<span>{msg.sender}</span>
<p>{msg.text}</p>
</div>
))}
<div ref={bottomRef} />
</div>
);
}メッセージ入力コンポーネント
Enter キーまたはボタンのクリックで送信する制御された入力です。送信後に入力欄をクリアします。
function MessageInput({ onSend }: { onSend: (text: string) => void }) {
const [text, setText] = useState('');
const handleSend = () => {
if (!text.trim()) return;
onSend(text.trim());
setText('');
};
return (
<div className="input-row">
<input
value={text}
onChange={e => setText(e.target.value)}
onKeyDown={e => e.key === 'Enter' && handleSend()}
placeholder="Type a message..."
/>
<button onClick={handleSend}>Send</button>
</div>
);
}チャット UI の組み立て
フックとサブコンポーネントを ChatRoom コンポーネントに組み合わせます。
function ChatRoom({ roomId }: { roomId: string }) {
const { messages, sendMessage } = useChat(roomId);
return (
<div className="chat-room">
<h2>Room: {roomId}</h2>
<MessageList messages={messages} />
<MessageInput onSend={sendMessage} />
</div>
);
}楽観的更新
サーバーの確認前にメッセージをローカルの状態へ即座に追加し、すぐにフィードバックを返します。サーバーがエラーを返した場合は、状態を調整するかメッセージを削除します。
const sendMessage = useCallback((text: string) => {
const optimistic: Message = { id: crypto.randomUUID(), text, sender: 'me', timestamp: Date.now() };
setMessages(m => [...m, optimistic]); // instant feedback
socket.emit('message', optimistic, (err) => {
if (err) setMessages(m => m.filter(msg => msg.id !== optimistic.id));
});
}, []);入力中インジケーター
入力が変更されたときに(デバウンスして)typing イベントを発行し、他のユーザーの typing イベントをリッスンしてインジケーターを表示します。
const emitTyping = useMemo(() => debounce(() => socket.emit('typing'), 300), []);
useEffect(() => {
socket.on('user-typing', (user) => setTypingUser(user));
return () => socket.off('user-typing');
}, []);メッセージのタイムスタンプ
Intl.DateTimeFormat でタイムスタンプをフォーマットすると、ロケールに応じた表示ができます。
function formatTime(ts: number) {
return new Intl.DateTimeFormat('en', { hour: '2-digit', minute: '2-digit' }).format(ts);
}
<span className="timestamp">{formatTime(msg.timestamp)}</span>既読通知
ユーザーがメッセージを表示したときに read イベントを発行し、サーバーからの既読確認をリッスンしてチェックマークを表示します。
仮想化されたメッセージ一覧
長いチャット履歴には、react-window または react-virtual を使用してメッセージ一覧を仮想化し、表示中の行だけをレンダーします。
メッセージ履歴の制限
長時間のセッションでメモリ使用量が際限なく増加しないよう、状態内の messages 配列に上限を設けます。
socket.on('message', (msg: Message) => {
setMessages(prev => [...prev.slice(-499), msg]); // keep last 500
});クイックチェック
チャット一覧に新しいメッセージが届いたとき、末尾の sentinel div までスクロールする目的は何ですか?
まとめ
ソケットのロジックをまとめた useChat フック、自動スクロールに対応した MessageList、送信時に入力をクリアする MessageInput を使って、リアルタイムチャットを構築します。すぐにフィードバックを返すには楽観的更新を使用し、メモリリークを防ぐためにメッセージ履歴に上限を設けます。
よくある質問
「リアルタイムチャットコンポーネントの構築」レッスンは無料ですか?
はい。「リアルタイムチャットコンポーネントの構築」の完全なテキストはこのウェブで無料で読めます。インタラクティブに演習し(組み込みコードエディタと24時間対応のAIチューター)、React Academyコースの残りをアンロックするには、CoddyKit PROにアップグレードしてください。 React Academyコースには全4レッスンが含まれています。
「リアルタイムチャットコンポーネントの構築」で何を学びますか?
WebSocket eventsとReact stateを使い、スクロール可能なチャットリストにリアルタイムのメッセージを表示します。 ブラウザで直接実行するハンズオンコードでReact Academyを演習し、24時間対応のAIチューターがレッスンを進める中での質問に答えます。
React Academyを始めるのに経験は必要ですか?
事前経験は必要ありません。CoddyKitのReact Academyは初級者から上級者向けに構成されているため、ここから始めるか最初から始めて、自分のペースで進むことができます。 これはレッスン3/4です。
「リアルタイムチャットコンポーネントの構築」レッスンにはどのくらい時間がかかりますか?
ほとんどのCoddyKitレッスンは約5~10分かかります。各レッスンはコンパクトでインタラクティブなので、着実に進歩し、ウェブとアプリ全体で正確に前回の場所から再開できます。
このReact Academyレッスンでコードを書いて実行できますか?
はい。すべてのReact Academyレッスンに組み込みコードエディタが含まれているため、ブラウザでリアルコードを書いて実行し、即座のAIフィードバックを取得できます。ローカル設定は不要です。
このコースのすべてのレッスン
- ブラウザで学ぶWebSocketの基礎
- ReactでSocket.IOを使う
- リアルタイムチャットコンポーネントの構築
- 再接続、エラー処理、クリーンアップ