新しいものを学ぶ👋#
最近、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):発生したイベントをリッスンします。
//xxxイベントをリッスンし、渡されたdataオブジェクトを出力します。
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 のストアを props として受け取り、context を介して下に渡し、connect 関数が Provider から渡されたストアを受け取り、state と actionCreator を props としてコンポーネントに渡すことができるようになります。コンポーネントは props の action を呼び出すことで reducer 関数をトリガーし、新しい state を返します。connect は変更を検知し、setState を呼び出してコンポーネントを更新し、新しい state を渡します。
redux-thunkの役割:store.dispatch を関数 / オブジェクトを受け取ることができるミドルウェアに変えます。
本来オブジェクトしか受け取れない store.dispatch を関数 / オブジェクトを受け取れるようにし、関数を受け取った場合は自動的にその関数を実行し、redux の store を更新しないようにします。
最後に💻#
Google、baidu などの検索エンジンと Google 翻訳😵に感謝します。
そして、bailicangduさんのreact-pxqプロジェクトの参考とまとめ😘