介紹
聊天室都會想到使用 Socket.io來製作,因為有持續監聽與 Server Side 可以主動 PUSH 的特性,一般的網頁方式就要定期去發Request,相對之下Socket.io在聊天室這類應用是比較好的選擇
安裝 socket.io套件
"isomorphic-unfetch"
"socket.io"
"socket.io-client"
Server 起一個 Scoket.io 服務 const io = require('socket.io')(server)
使用io.on 第一個參數建立連線 connection ,第二個參數 監聽 socket 使用 socket.on('message'),
當client端有送出 message event, server 監聽到 client 傳來 message 時就把 data 推到 DB(這邊用一個假的陣列替代),接著使用 socket.broadcast.emit('message', data) 把這筆接收到的 data 再推倒前端 client 如果有建立連線 就會收到server 傳來的 data
server side
省略...
const io = require('socket.io')(server)
// 假資料庫
const messages = []
// socket.io server
io.on('connection', socket => {
socket.on('message', (data) => {
messages.push(data)
socket.broadcast.emit('message', data)
})
})
nextApp.prepare().then(() => {
app.get('/messages', (req, res) => {
res.json(messages)
})
省略...
})
restful部分使用一個 messages 可以 撈到所有的資料
client Side
isomorphic-unfetch 是一個 server 的fetch polyfill 在使用ssr的時候記得補上,SSR先同步所有 Message
import { Component } from 'react'
import io from 'socket.io-client'
import fetch from 'isomorphic-unfetch'
class HomePage extends Component {
// 同步 SSR 所有目前 Message
static async getInitialProps ({ req }) {
const response = await fetch('http://localhost:3000/messages')
const messages = await response.json()
return { messages }
}
static defaultProps = {
messages: []
}
// 初始化 state
state = {
field: '',
messages: this.props.messages
}
// 連結socket並監聽server打來的資訊
componentDidMount () {
this.socket = io()
this.socket.on('message', this.handleMessage)
}
// 結束對server的監聽
componentWillUnmount () {
this.socket.off('message', this.handleMessage)
this.socket.close()
}
// 如果Server有打回資料就使用 concat 疊加上去
handleMessage = (message) => {
this.setState(state => ({ messages: state.messages.concat(message) }))
}
handleChange = event => {
this.setState({ field: event.target.value })
}
// 使用form 因為是SPA所以阻止 form表單的 submit (event.preventDefault())
handleSubmit = event => {
event.preventDefault()
// 創建要塞到後端的object
const message = {
id: (new Date()).getTime(),
value: this.state.field
}
// 推送到後端
this.socket.emit('message', message)
// 使用 concat 疊加到state.message
this.setState(state => ({
field: '',
messages: state.messages.concat(message)
}))
}
以下省略....
}
export default HomePage
總結
在使用 Next.js 開發 socket.io 只需注意 SSR 部分,初始話部分記得先使用 fetch 同步一下資訊,其他 socket.io開發模式跟一般開發一樣
官方 github範例
https://github.com/zeit/next.js/tree/canary/examples/with-socket.io