From 1bb20b1930fb9d849c8e091847664cd1c6b91b40 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Sergio=20Daniel=20Xalambr=C3=AD?= Date: Sat, 22 Apr 2017 07:53:48 -0500 Subject: [PATCH] Add socket.io example (#1766) * Add socket.io example * [update] stop handling events before unmount * [update] add deploy to now button * Fix linting problems * Fix last missing linting problem --- examples/with-socket.io/README.md | 25 ++++++++ examples/with-socket.io/package.json | 16 +++++ examples/with-socket.io/pages/index.js | 88 ++++++++++++++++++++++++++ examples/with-socket.io/server.js | 34 ++++++++++ 4 files changed, 163 insertions(+) create mode 100644 examples/with-socket.io/README.md create mode 100644 examples/with-socket.io/package.json create mode 100644 examples/with-socket.io/pages/index.js create mode 100644 examples/with-socket.io/server.js diff --git a/examples/with-socket.io/README.md b/examples/with-socket.io/README.md new file mode 100644 index 00000000..1b35df46 --- /dev/null +++ b/examples/with-socket.io/README.md @@ -0,0 +1,25 @@ +[![Deploy to now](https://deploy.now.sh/static/button.svg)](https://deploy.now.sh/?repo=https://github.com/zeit/next.js/tree/master/examples/with-socket.io) + +# Socket.io example + +## How to use + +Download the example [or clone the repo](https://github.com/zeit/next.js): + +```bash +curl https://codeload.github.com/zeit/next.js/tar.gz/master | tar -xz --strip=2 next.js-master/examples/with-socket.io +cd with-socket.io +``` + +Install it and run: + +```bash +npm install +npm run dev +``` + +## The idea behind the example + +This example show how to use [socket.io](https://socket.io/) inside a Next.js application. It uses `getInitialProps` to fetch the old messages from a HTTP endpoint as if it was a Rest API. The example combine the WebSocket server with the Next server, in a production application you should split them as different services. + +**Example:** [https://next-socket-io.now.sh/](https://next-socket-io.now.sh/) diff --git a/examples/with-socket.io/package.json b/examples/with-socket.io/package.json new file mode 100644 index 00000000..0248bc81 --- /dev/null +++ b/examples/with-socket.io/package.json @@ -0,0 +1,16 @@ +{ + "dependencies": { + "express": "^4.15.2", + "isomorphic-fetch": "^2.2.1", + "next": "latest", + "react": "^15.5.4", + "react-dom": "^15.5.4", + "socket.io": "^1.7.3", + "socket.io-client": "^1.7.3" + }, + "scripts": { + "dev": "node server.js", + "build": "next build", + "start": "NODE_ENV=production node server.js" + } +} diff --git a/examples/with-socket.io/pages/index.js b/examples/with-socket.io/pages/index.js new file mode 100644 index 00000000..578fb9e3 --- /dev/null +++ b/examples/with-socket.io/pages/index.js @@ -0,0 +1,88 @@ +import { Component } from 'react' +import io from 'socket.io-client' +import fetch from 'isomorphic-fetch' + +class HomePage extends Component { + // fetch old messages data from the server + static async getInitialProps ({ req }) { + const response = await fetch('http://localhost:3000/messages') + const messages = await response.json() + return { messages } + } + + static defaultProps = { + messages: [] + } + + // init state with the prefetched messages + state = { + field: '', + messages: this.props.messages + } + + // connect to WS server and listen event + componentDidMount () { + this.socket = io('http://localhost:3000/') + this.socket.on('message', this.handleMessage) + } + + // close socket connection + componentWillUnmount () { + this.socket.off('message', this.handleMessage) + this.socket.close() + } + + // add messages from server to the state + handleMessage = (message) => { + this.setState(state => ({ messages: state.messages.concat(message) })) + } + + 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.socket.emit('message', message) + + // add it to state and clean current input value + this.setState(state => ({ + field: '', + messages: state.messages.concat(message) + })) + } + + render () { + return ( +
+
+
    + {this.state.messages.map(message => +
  • {message.value}
  • + )} +
+
+ + +
+
+
+ ) + } +} + +export default HomePage diff --git a/examples/with-socket.io/server.js b/examples/with-socket.io/server.js new file mode 100644 index 00000000..d9895fb5 --- /dev/null +++ b/examples/with-socket.io/server.js @@ -0,0 +1,34 @@ +const app = require('express')() +const server = require('http').Server(app) +const io = require('socket.io')(server) +const next = require('next') + +const dev = process.env.NODE_ENV !== 'production' +const nextApp = next({ dev }) +const nextHandler = nextApp.getRequestHandler() + +// fake DB +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) + }) + + app.get('*', (req, res) => { + return nextHandler(req, res) + }) + + server.listen(3000, (err) => { + if (err) throw err + console.log('> Ready on http://localhost:3000') + }) +})