Magren

Magren

Idealist & Garbage maker 🛸
twitter
jike

關於ChatRoom

學習新東西👋#

最近這幾天在學習 React,所以這個專案主要目的是讓我熟悉 React,我個人是喜歡邊學習一樣新東西邊動手,只有輸出才會讓我記憶更深刻,其次也會踩到一些光看是不會碰到的坑,加上之前學習 node.js 好像也沒有做什麼,於是就想到了結合在一塊做一個聊天室。✌

因為是第一次做 React,如果覺得有什麼需要修改的歡迎提出Issuse,也歡迎你的 star⭐

專案地址:ChatRoom

專案截圖:
1.png
2.png
3.png

後端#

後端基於 Node.js + Express + Socket.io + MongoDB
Node.js 操作 MongoDB 以及用 express 寫接口之前都有在博客中大致的總結過:
Node.js+express
Node.Js 操作 MongoDB
這次用的新東西就是 Socket.io。

前人的工作👇#

Socket.IO is a library that enables real-time, bidirectional and event-based communication between the browser and the server

即是說 Socket.io 可以實現伺服器與客戶端之間的一個實時的雙向通訊。
在連接 Socket.io 的之前還得先知道WebSocket,在 WebSocket 問世之前,在創建擁有雙向通訊機制的 web 應用程序時,就只能利用 HTTP 輪詢的方式,由此產生了 “短輪詢” 和 “長輪詢”。

短輪詢通過客戶端定期輪詢來詢問服務端是否有新的信息產生,缺點也是顯而易見,輪詢間隔大了則信息不夠實時,輪詢間隔過小又會消耗過多的流量,增加伺服器的負擔。
長輪詢是對短輪詢的優化,需要服務端做相應的修改來支持。但是每次請求還是都要帶上 HTTP 請求頭部,而且在長輪詢的連接結束之後,伺服器端積累的新消息要等到下次客戶端連接時才能傳遞。

Websocket 協議就是為了解決長輪詢的痛點而誕生的,其基於 TCP 協議,是一種雙全工通訊技術、複用 HTTP 握手通道。它與 HTTP 協議的唯一關係就是它的握手請求可以作為一個Upgrade request經由 HTTP 伺服器解析,且與 HTTP 使用一樣的端口。

接著是Socket.io,Socket.io 底層基於engine.io,封裝了 WebSocket,其屏蔽了底層細節,讓頂層調用非常簡單。同時它還支持許多種輪詢機制以及其他通訊方式,當環境不支持 WebSocket 的時候它能自動選擇最佳的方式來實現網路的實時通訊。

使用#

引入 io 設置端口後監聽 connect 事件:

const server = require('http').Server(app);  
const io = require('socket.io')(server);  

server.listen(3001); //端口設置3001

io.on(('connection', socket=>{
    
    ………………

})

接著通過最重要的兩個 api,emiton來發送以及監聽事件

  • socket.emit (eventName,[ ...args]):發射(觸發)一個事件
  • socket.on (eventName, callback):監聽一個 emit 發射的事件
//監聽xxx事件,輸出傳進來的data對象
socket.on('xxx',data=>{
  console.log(data);
})
//發送xxx事件,傳出去一個對象,裡面有name屬性
socket.emit('xxx',{name:'magren'})

另外用到的方法

  • socket.join (id):加入到一個 room 為 id 的房間中
  • socket.broadcast.to (id).emit ( ):廣播給 room 為 id 的除了‘我’以外的所有人
  • io.sockets.in (id).emit ( ):廣播給 room 為 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-reduxredux-thunk 兩個庫。

使用了 react-redux 後流程大大縮短,store 的三大功能: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專案的參考以及總結😘

載入中......
此文章數據所有權由區塊鏈加密技術和智能合約保障僅歸創作者所有。