新しいものを学ぶ👋#
最近、React を学んでいるので、このプロジェクトの主な目的は React に慣れることです。私は個人的に、新しいものを学ぶときには実際に手を動かすことが好きです。出力しないと、記憶に残りません。また、見ているだけではわからない問題にも遭遇することがあります。また、以前に Node.js を学んだことがなかったので、チャットルームを作ることを思いつきました。✌
React を初めて使うので、修正が必要な点があれば、Issuseで提案していただければ幸いです。また、スター⭐も歓迎です。
プロジェクトのリンク:ChatRoom
プロジェクトのスクリーンショット:
バックエンド#
バックエンドは Node.js + Express + Socket.io + MongoDB を使用しています。
Node.js で MongoDB を操作し、express で API を作成する方法については、以前にブログでまとめたことがあります。
Node.js+express
Node.Js で MongoDB を操作する
今回は Socket.io という新しいものを使用しています。
前人の仕事👇#
Socket.IO は、ブラウザとサーバー間のリアルタイムで双方向のイベントベースの通信を可能にするライブラリです。
つまり、Socket.IO を使用すると、サーバーとクライアント間でリアルタイムの双方向通信ができます。
Socket.IO を接続する前に、WebSocketについて知っておく必要があります。WebSocket が登場する前は、双方向通信を持つ Web アプリケーションを作成するために、HTTP ポーリングのみを利用することができました。これにより、「ショートポーリング」と「ロングポーリング」が生まれました。
ショートポーリングは、クライアントが定期的にサーバーに新しい情報があるかどうかを問い合わせることで、情報がリアルタイムではないという欠点があります。ポーリング間隔が長すぎると情報がリアルタイムではありませんし、ポーリング間隔が短すぎると多くのトラフィックが発生し、サーバーの負荷が増加します。
ロングポーリングは、ショートポーリングの最適化ですが、サーバー側での変更が必要です。ただし、各リクエストで HTTP リクエストヘッダを送信する必要があり、ロングポーリングの接続が終了した後、サーバー側で蓄積された新しいメッセージは、次回のクライアント接続時まで送信できません。
WebSocket プロトコルは、ロングポーリングの問題を解決するために作成されました。WebSocket は TCP プロトコルを基にしており、フルデュプレックス通信技術であり、HTTP のハンドシェイクチャネルを再利用します。WebSocket と HTTP の関係は、ハンドシェイクリクエストが HTTP サーバーによって解析されることができるため、HTTP サーバーを介してアップグレードリクエストとして処理されることです。
次に、Socket.ioです。Socket.io は、engine.ioをベースにしており、WebSocket をカプセル化しています。Socket.io は、低レベルの詳細を隠蔽し、トップレベルの呼び出しを非常に簡単にします。さらに、さまざまなポーリングメカニズムやその他の通信方法もサポートしており、環境が WebSocket をサポートしていない場合でも、ネットワークのリアルタイム通信を実現するために最適な方法を自動的に選択します。
使用方法#
io をインポートし、ポートを設定して connect イベントをリッスンします:
const server = require('http').Server(app);
const io = require('socket.io')(server);
server.listen(3001); //ポートを3001に設定
io.on(('connection', socket=>{
………………
})
次に、最も重要な 2 つの API、emitとonを使用してイベントを送信およびリッスンします。
- socket.emit (eventName,[ ...args]):イベントを送信します
- socket.on (eventName, callback):emit で送信されたイベントをリッスンします
//xxxイベントをリッスンし、渡されたデータオブジェクトを出力します
socket.on('xxx',data=>{
console.log(data);
})
//xxxイベントを送信し、nameプロパティを持つオブジェクトを送信します
socket.emit('xxx',{name:'magren'})
その他のメソッド
- socket.join (id):id という名前のルームに参加します
- socket.broadcast.to (id).emit ( ):' 私 ' 以外のルーム id のすべての人にブロードキャストします
- io.sockets.in (id).emit ( ):ルーム id のすべての人にブロードキャストします
フロントエンド#
フロントエンドは React + Redux + Typescript + Antd を使用しています。
バックエンドにメッセージを送信し、リッスンするのは非常に簡単で、単にsocket.io-clientをインポートし、emit を使用してイベントを送信し、on を使用してイベントをリッスンします。
const socket = require('socket.io-client')('ws://localhost:3001',{transports: ['websocket']})
//メッセージをリッスンする
socket.on('chat_message',(data: mesItem)=>{
this.setState({
message:[data,...this.state.message]
});
})
//グループに参加するメッセージを送信する
socket.emit('join', {
roomId:this.props.match.params.roomId,
userName:this.props.state.name,
userId:this.props.state.id
})
//メッセージを送信する
socket.emit('mes',{
roomId:this.props.match.params.roomId,
userName:this.props.state.name,
userId:this.props.state.id,
mes:this.state.msg
})
Redux について#
redux と vuex の理念は同じように感じます。どちらも状態管理ライブラリであり、メモリに保存されます(リフレッシュするとリセットされます)。グローバルな state を定義し、アクションをトリガーとして state を変更します。違いもありますが、Vuex のデータは変更可能で直接変更できますが、Redux は不変であり、新しい state で古い state を置き換えます。
このプロジェクトでは、**react-reduxとredux-thunk** の 2 つのライブラリを使用しています。
react-redux を使用すると、ストアの 3 つの機能である dispatch、subscribe、getState を大幅に短縮できます。Provider と Connect を提供しており、前者はコンポーネントであり、後者は関数です。
大まかな流れは、Provider コンポーネントが redux の store を props として受け取り、context を介して下位に渡し、connect 関数が Provider から渡された store を受け取り、state と actionCreator を props としてコンポーネントに渡すことで、コンポーネントは props 内の action を呼び出して reducer 関数をトリガーし、新しい state を返します。connect は変更を監視し、setState を呼び出してコンポーネントを更新し、新しい state を渡します。
redux-thunkの役割:store.dispatch を関数 / オブジェクトを受け取ることができるミドルウェアに変えます。
元々オブジェクトしか受け取れなかった store.dispatch を、オブジェクト / 関数を受け取れるようにし、関数を受け取った場合は自動的にその関数を実行し、redux の store の更新をトリガーしません。
最後に💻#
Google、baidu などの検索エンジンと Google 翻訳😵に感謝します。
そして、bailicangduさんのreact-pxqプロジェクトの参考とまとめに感謝します😘