1
0
Fork 0
mirror of https://github.com/terribleplan/next.js.git synced 2024-01-19 02:48:18 +00:00

with-socket.io Example updated with _app.js (#4644)

with-socket.io example was using a single index file and was managing connection in there. This would lead handling connection (disconnecting and reconnecting) in each added page.

I updated example with addition of `_app.js` and handled connection in there. This helped only subscribing to event in page and maintaining connection throughout example.
This commit is contained in:
Bünyamin Benny Genel 2018-06-23 23:17:37 +03:00 committed by Tim Neutkens
parent f4af03b9c8
commit 6ed2da4575
4 changed files with 202 additions and 18 deletions

View file

@ -0,0 +1,39 @@
import App, {Container} from 'next/app'
import React from 'react'
import io from 'socket.io-client'
class MyApp extends App {
static async getInitialProps ({ Component, ctx }) {
let pageProps = {}
if (Component.getInitialProps) {
pageProps = await Component.getInitialProps(ctx)
}
return { pageProps }
}
state = {
socket: null
}
componentDidMount () {
// connect to WS server and listen event
const socket = io()
this.setState({ socket })
}
// close socket connection
componentWillUnmount () {
this.state.socket.close()
}
render () {
const {Component, pageProps} = this.props
return (
<Container>
<Component {...pageProps} socket={this.state.socket} />
</Container>
)
}
}
export default MyApp

View file

@ -0,0 +1,113 @@
import { Component } from 'react'
import Link from 'next/link'
import fetch from 'isomorphic-unfetch'
class ChatTwo extends Component {
// fetch old messages data from the server
static async getInitialProps ({ req }) {
const response = await fetch('http://localhost:3000/messages/chat2')
const messages = await response.json()
return { messages }
}
static defaultProps = {
messages: []
}
// init state with the prefetched messages
state = {
field: '',
newMessage: 0,
messages: this.props.messages,
subscribe: false,
subscribed: false
}
subscribe = () => {
if (this.state.subscribe && !this.state.subscribed) {
// connect to WS server and listen event
this.props.socket.on('message.chat2', this.handleMessage)
this.props.socket.on('message.chat1', this.handleOtherMessage)
this.setState({ subscribed: true })
}
}
componentDidMount () {
this.subscribe()
}
componentDidUpdate () {
this.subscribe()
}
static getDerivedStateFromProps (props, state) {
if (props.socket && !state.subscribe) return { subscribe: true }
return null
}
// close socket connection
componentWillUnmount () {
this.props.socket.off('message.chat1', this.handleOtherMessage)
this.props.socket.off('message.chat2', this.handleMessage)
}
// add messages from server to the state
handleMessage = (message) => {
this.setState(state => ({ messages: state.messages.concat(message) }))
}
handleOtherMessage = () => {
this.setState((prevState) => ({ newMessage: (prevState.newMessage + 1) }))
}
handleChange = event => {
this.setState({ field: event.target.value })
}
// send messages to server and add them to the state
handleSubmit = event => {
event.preventDefault()
// create message object
const message = {
id: (new Date()).getTime(),
value: this.state.field
}
// send object to WS server
this.props.socket.emit('message.chat2', message)
// add it to state and clean current input value
this.setState(state => ({
field: '',
messages: state.messages.concat(message)
}))
}
render () {
return (
<main>
<div>
<Link href={'/'}><a>{`Chat One ${this.state.newMessage > 0 ? `( ${this.state.newMessage} new message )` : ''}`}</a></Link>
<br />
<Link href={'/clone'}><a>{'Chat Two'}</a></Link>
<ul>
{this.state.messages.map(message =>
<li key={message.id}>{message.value}</li>
)}
</ul>
<form onSubmit={(e) => this.handleSubmit(e)}>
<input
onChange={this.handleChange}
type='text'
placeholder='Hello world!'
value={this.state.field}
/>
<button>Send</button>
</form>
</div>
</main>
)
}
}
export default ChatTwo

View file

@ -1,11 +1,11 @@
import { Component } from 'react'
import io from 'socket.io-client'
import Link from 'next/link'
import fetch from 'isomorphic-unfetch'
class HomePage extends Component {
class ChatOne extends Component {
// fetch old messages data from the server
static async getInitialProps ({ req }) {
const response = await fetch('http://localhost:3000/messages')
const response = await fetch('http://localhost:3000/messages/chat1')
const messages = await response.json()
return { messages }
}
@ -17,19 +17,37 @@ class HomePage extends Component {
// init state with the prefetched messages
state = {
field: '',
messages: this.props.messages
newMessage: 0,
messages: this.props.messages,
subscribe: false,
subscribed: false
}
subscribe = () => {
if (this.state.subscribe && !this.state.subscribed) {
// connect to WS server and listen event
this.props.socket.on('message.chat1', this.handleMessage)
this.props.socket.on('message.chat2', this.handleOtherMessage)
this.setState({ subscribed: true })
}
}
componentDidMount () {
this.socket = io()
this.socket.on('message', this.handleMessage)
this.subscribe()
}
componentDidUpdate () {
this.subscribe()
}
static getDerivedStateFromProps (props, state) {
if (props.socket && !state.subscribe) return { subscribe: true }
return null
}
// close socket connection
componentWillUnmount () {
this.socket.off('message', this.handleMessage)
this.socket.close()
this.props.socket.off('message.chat1', this.handleMessage)
this.props.socket.off('message.chat2', this.handleOtherMessage)
}
// add messages from server to the state
@ -37,6 +55,10 @@ class HomePage extends Component {
this.setState(state => ({ messages: state.messages.concat(message) }))
}
handleOtherMessage = () => {
this.setState((prevState) => ({ newMessage: (prevState.newMessage + 1) }))
}
handleChange = event => {
this.setState({ field: event.target.value })
}
@ -52,7 +74,7 @@ class HomePage extends Component {
}
// send object to WS server
this.socket.emit('message', message)
this.props.socket.emit('message.chat1', message)
// add it to state and clean current input value
this.setState(state => ({
@ -65,12 +87,15 @@ class HomePage extends Component {
return (
<main>
<div>
<Link href={'/'}><a>{'Chat One'}</a></Link>
<br />
<Link href={'/clone'}><a>{`Chat Two ${this.state.newMessage > 0 ? `( ${this.state.newMessage} new message )` : ''}`}</a></Link>
<ul>
{this.state.messages.map(message =>
<li key={message.id}>{message.value}</li>
)}
</ul>
<form onSubmit={this.handleSubmit}>
<form onSubmit={(e) => this.handleSubmit(e)}>
<input
onChange={this.handleChange}
type='text'
@ -85,4 +110,4 @@ class HomePage extends Component {
}
}
export default HomePage
export default ChatOne

View file

@ -9,19 +9,26 @@ const nextApp = next({ dev })
const nextHandler = nextApp.getRequestHandler()
// fake DB
const messages = []
const messages = {
chat1: [],
chat2: []
}
// socket.io server
io.on('connection', socket => {
socket.on('message', (data) => {
messages.push(data)
socket.broadcast.emit('message', data)
socket.on('message.chat1', (data) => {
messages['chat1'].push(data)
socket.broadcast.emit('message.chat1', data)
})
socket.on('message.chat2', (data) => {
messages['chat2'].push(data)
socket.broadcast.emit('message.chat2', data)
})
})
nextApp.prepare().then(() => {
app.get('/messages', (req, res) => {
res.json(messages)
app.get('/messages/:chat', (req, res) => {
res.json(messages[req.params.chat])
})
app.get('*', (req, res) => {