導入
既に実装済みのサーバーをベースに、ReactJS でシンプルなチャットアプリケーションを構築します。まず静的コンポーネントを作成し、それらを状態に接続します。最後に、イベントサーバーをサブスクライブします。.
前提条件
- JavaScript と ReactJS の基礎知識(シンプルにまとめています)
- npm v6
- npx v6
- ノードv12
ステップ1: プロジェクトを開始する
プロジェクトフォルダで npx create-react-app --use-npm simple-chat-app を実行し、インストールが完了するまでお待ちください。これにより必要な依存関係がすべて追加され、シンプルな開発とビルド環境が提供されます。.
次のファイルを src フォルダーに追加します。
- App.js (すでに存在しているはずです)
- チャットラインホルダー.js
- チャットライン.js
- チャット入力.js
コンソールのプロジェクトフォルダから npm run start を実行してください。これにより開発サーバーが起動し、デフォルトのブラウザでアプリケーションが開きます。.
srcフォルダにはすでにApp.jsファイルがあるはずです。今のところは、返されるものをすべて削除して、1つだけ残しておいて構いません。 <div> 返して下さい。.
const App = () => {
return <div className='chat-app'></div>
}まず、コンポーネントを下から作成していきます。
ステップ2: コンポーネント
ChatLine.js では、次の 2 つのプロパティを持つ新しいコンポーネントを作成します。
名前: 弦メッセージ: 弦
これは、後でイベント データとしてサーバーから受信するデータです。.
コンポーネント1
import React from 'react'
const ChatLine = ({ name, message }) => {
return (
<li>
{name}: {message}
</li>
)
}
export default注: ReactJS は HTML インジェクションを自動的に防止するため、心配する必要はありません。.
ステップ3: コンポーネント
ChatHolder.js では、1 つのベースのみを受け取る新しいコンポーネントを作成します。
行: 配列<{ name: string, message: string }>
もし 線 空の場合は、簡単な通知が表示されます。.
if (lines.length === 0) {
return <div>Chat history is empty</div>
}Lines はオブジェクトの配列です。各オブジェクトには名前とプロパティメッセージがあります。名前と文字列をコンポーネントに渡すことで、配列内のすべての項目をマッピングし、結果を取得します。複数の ChatLine ノードを作成します。.
const chatLines = lines.map(
(line, index) => (
<ChatLine key={index} name={line.name} message={line.message} />
)
)その結果は
- レンダリングすると、完成したコンポーネントが残ります。
- onSend: (メッセージ: 文字列) => void
- name: チャットしているユーザーの名前。
- chatLines: チャット履歴を表す配列。
- eventLister: サーバーからのイベントを管理するために使用されます。(注: リスナーを部分に配置することにしました。.
- サーバーにメッセージを送信
- サーバーから送信されたイベントを購読する
import React from 'react'
import ChatLine from './ChatLine'
const ChatLineHolder = ({ lines }) => {
if (lines.length === 0) {
return <div>Chat history is empty</div>
}
const chatLines = lines.map(
(line, index) => (
<ChatLine key={index} message={line.message} name={line.name} />
)
)
return (
<ul>
{chatLines}
</ul>
)
}
export default ChatLineHolder注: 通常、キーには一意の識別子を使用します。この場合、インデックスとオブジェクトの関連付けは変更されないため、インデックスを安全に使用できます。ただし、実際のアプリケーションでは、これは非常に煩わしい場合があります。.
ステップ4: コンポーネント
お気づきかもしれませんが、メッセージをインポートする方法はまだありません。テキスト入力を処理し、送信時にコールバック関数を使用してボタンクリック時に新しいチャットメッセージを起動します。必要なプロパティ:
ユーザー入力コンポーネントは状態を保持し、更新を管理します。.
const [value, setValue] = useState('')
const onChange = (event) => {
setValue(event.target.value)
}送信ボタンがクリックされると、現在の状態を引数としてonSend関数が呼び出されます。ユーザーが入力フィールドを手動でクリアする手間を省くため、onSend関数を呼び出した後、状態をリセットします。.
const onClickSend = () => {
onSend(value)
setValue('')
}
最後のコンポーネントは次のとおりです。
import React, { useState } from 'react'
const ChatInput = ({ onSend }) => {
const [value, setValue] = useState('')
const onChange = (event) => {
setValue(event.target.value)
}
const onClickSend = () => {
setValue('')
onSend(value)
}
return (
<div>
<input type='text' value={value} onChange={onChange} />
<button onClick={onClickSend}>send</button>
</div>
)
}
export default ChatInputステップ5: コンポーネント
モード
コンポーネントはデータを保存しないため、状態管理に使用する主要コンポーネントです。状態には3種類あります。
(簡潔にするために、実際のアプリケーションでは異なるアプローチを取る必要があるかもしれません。)
状態を初期化するには状態フックを使用します。
const [chatLines, setChatLines] = useState([])
const [eventListener, setEventListener] = useState(null)
const [name] = useState(generateRandomName())コンポーネントレンダリングテスト
今は名前とコンポーネントを表示するだけです固定アイテムを含むチャットラインを表示します。チャットラインは空の配列なので、通知を提供する必要があります。空のフラッシュ関数を呼び出して、送信いたします。実行は次のステップで行います。.
return (
<div className='chat-app'>
<h2>Chatting as {name}</h2>
<ChatLineHolder lines={chatLines} />
<ChatInput onSend={() => {}} />
</div>
)実装が何らかのデータで機能するかどうかを確認する場合は、chatLines にいくつかの項目を追加するだけです。.
const [chatLines, setChatLines] = useState([{ name: 'Thomas', 'message': 'Hi' }])
インタラクションを追加する
チャット入力欄にテキストを入力することはできますが、送信ボタンを押しても何も起こりません。これは、全く何もしないものを送りました。そのため、実装が必要です。.
まだサーバーに接続していないため、onSend を実装して状態を直接更新します。そのために、ヘルパー関数 addChatLine: (chatLine) => void を追加します。この関数は、後ほどサーバーから送信されたメッセージイベントを処理するために使用します。.
const addChatLine = (chatLine) => {
setChatLines(chatLines => {
return [...chatLines, chatLine]
})
// If you don't have a lot of experience with ReactJS, just think of this as:
// setChatLines([...chatLines, chatLine])
}onSendはチャットラインオブジェクトを作成し、addChatLineを呼び出します。
const onSend = (message) => {
const chatLine = { name, message }
addChatLine(chatLine)
}忘れずに送ってください送信。.
return (
<div className='chat-app'>
<h2>Chatting as {name}</h2>
<ChatLineHolder lines={chatLines} />
<ChatInput onSend={onSend} />
</div>
)これで、入力フィールドにテキストを入力し、「送信」をクリックすると、すぐにメッセージが表示されるようになります。.
ステップ6: サーバーに接続する
独り言を言うのはとても退屈です。だからこそ、アプリケーションをサーバーに接続する必要があります。これは2つの部分で行われます。
サーバーにメッセージを送信
先ほど記述した onSend 関数を修正する必要があります。ボディ全体を、名前とメッセージをボディに送信する単純な fetch 呼び出しに置き換えます。addChatLine は呼び出さないようにしましょう。これは、後でサーバーから送信されたイベントを受け取った際に呼び出されるからです。.
const onSend = async (message) => {
fetch('http://localhost:4000/say',
{
headers: {
'Content-Type': 'application/x-www-form-urlencoded',
},
method: 'post',
mode: 'no-cors',
body: `name=${name}&message=${message}`
})
}今「送信」ボタンをクリックすると、サーバーにリクエストが送信されますが、ステータスはまだ更新されません。この点については次のステップで対処します。.
サーバーから送信されたイベントを購読する
イベントのリッスンを始める前に、メッセージイベントを処理する関数が必要です。後ほどメッセージタイプのイベントに接続するので、それに応じて実装できます。この関数は、event.data を受け取り、それをオブジェクトに解析し、addChatLine を呼び出すだけです。.
const onMessage = (event) => {
const chatLine = JSON.parse(event.data)
addChatLine(chatLine)
}
サーバーから送信されたイベントを受信するには、ローカルアドレスを使用してEventSourceクラスのオブジェクトを作成します。次に、メッセージタイプのイベントリスナーを追加します。そして、それをuseEffectフックでラップします(これにより、コンポーネントがマウントされ、イベント ソースが初期化され、マウント後に閉じられます。.
useEffect(() => {
let source = new EventSource('http://localhost:4000/listen')
source.addEventListener('message', onMessage)
setEventSource(source)
return () => { source.close() }
}, [])成分最終的には次のようになります。
import React, { useEffect, useState } from 'react'
import ChatLineHolder from './ChatLineHolder'
import ChatInput from './ChatInput'
const App = () => {
const [chatLines, setChatLines] = useState([])
const [eventSource, setEventSource] = useState(null)
const [name] = useState(generateRandomName())
const addChatLine = (chatLine) => {
setChatLines(chatLines => [...chatLines, chatLine])
}
const onMessage = (event) => {
const chatLine = JSON.parse(event.data)
addChatLine(chatLine)
}
useEffect(() => {
let source = new EventSource("http://localhost:4000/listen")
source.addEventListener('message', onMessage)
setEventSource(source)
return () => { source.close() }
}, [])
const onSend = (message) => {
fetch(
`http://localhost:4000/say`,
{
headers: {
"Content-Type": "application/x-www-form-urlencoded",
},
method: "post",
mode: 'no-cors',
body: `name=${name}&message=${message}`,
})
}
return (
<div className='chat-app'>
<h2>Chatting as {name}</h2>
<ChatLineHolder lines={chatLines} />
<ChatInput onSend={onSend} />
</div>
)
}
export default App結果
これで、ページを2つのタブで開き、2人の分身とチャットできるようになりました!また、各インスタンスが独自の状態を持つため、Appコンポーネントを2回マウントすることもできます(index.jsを変更することで)。.









