Welcome to BoulderJS!
Building Platforms with React + WebSockets
What's React?
a JS library for building UI
What's a WebSocket?
a protocol for communication via channels
Normal Web Communication
visualization of the request / response cycle
WebSocket Communication
visualization of realtime communication
Why use them together?
providing new and engaging web experiences
https://alan-chat.herokuapp.com
https://sound-sockets.herokuapp.com
Putting the Pieces Together
https://github.com/alanbsmith/react-websocket-starter
// ./server.js
var path = require('path');
var express = require('express');
var app = express();
var PORT = process.env.PORT || 8080;
var server = require('http').createServer(app);
var io = require('socket.io')(server);
...
app.use(express.static(path.join(__dirname, 'dist')));
app.get('/', function(request, response) {
response.sendFile(__dirname + '/dist/index.html');
});
io.on('connection', function(client) {
client.on('join', function(data) {
console.log(data);
});
});
server.listen(PORT);
Webpack Setup
./server.js
...
// using webpack-dev-server and middleware in development environment
if (process.env.NODE_ENV !== 'production') {
var webpackDevMiddleware = require('webpack-dev-middleware');
var webpackHotMiddleware = require('webpack-hot-middleware');
var webpack = require('webpack');
var config = require('./webpack.config');
var compiler = webpack(config);
app.use(webpackDevMiddleware(compiler, {
noInfo: true,
publicPath: config.output.publicPath
}));
app.use(webpackHotMiddleware(compiler));
}
...
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
<title>Chat</title>
</head>
<body>
<div id='root'/>
</body>
<script src="/socket.io/socket.io.js"></script>
<script src="/bundle.js"></script>
</html>
./dist/index.html
View Setup
import '../assets/stylesheets/base.scss';
import React, { Component } from 'react';
let socket = io.connect();
const App = React.createClass({
componentDidMount() {
socket.on('connect', function(data) {
socket.emit('join', 'hello world from the client!');
});
},
render() {
return (
<h1>Hello, {this.props.name}!</h1>
)
}
});
export default App;
./src/components/App.js
Building our First Component
...
const App = React.createClass({
...
render() {
return(
<div>
<div className="header"></div>
<div>
<MessageList messages={this.state.messages} />
<MessageForm />
</div>
</div>
)
}
});
export default App;
./src/components/App.js
Adding Functionality
import moment from 'moment';
let socket = io.connect();
const MessageForm = React.createClass({
...
handleSubmit(e) {
e.preventDefault();
const text = this.refs.message.value.trim();
const time = moment().format("h:mm a");
this.refs.message.value = "";
socket.emit('new-message', { author: this.state.name, text: text, display_time: time });
},
...
render() {
return(
<div className="footer">
<form id="message-form" onSubmit={this.handleSubmit}>
<input ref="message" type="text" placeholder="type your message here" />
</form>
</div>
)
}
});
export default MessageForm;
./src/components/MessageForm.js
Publishing Message Data
io.on('connection', function(client) {
console.log('client connected!');
client.on('join', function(data) {
console.log(data);
});
client.on('new-message', function(data) {
io.sockets.emit('add-message', data);
});
});
./server.js
Listening on the Server
const App = React.createClass({
getInitialState() {
return { messages: [] };
},
...
componentDidMount() {
socket.on('connect', function(data) {
socket.emit('join', 'hello world from the client!');
});
socket.on('add-message', this._addMessage);
this.getMessages();
},
_addMessage(data) {
this.state.messages.push(data);
this.setState({ messages: this.state.messages });
},
});
./components/App.js
Updating the State
...
client.on('new-message', function(data) {
var promise = new Promise(function(resolve, reject) {
var messageData = { message: data };
requestClient.post('api/v1/messages', messageData, function(err, res, body) {
if(err) {
reject(err);
}
else {
io.sockets.emit('add-message', body);
}
})
});
});
...
./server.js
Persisting Data
const Room = React.createClass({
getInitialState() {
return({
userName: "",
channelId: `channel-${this.props.params.id}`,
name: "",
messages: [],
})
},
componentDidMount() {
socket.emit('join', this.state.channelId );
socket.on('new-message', this._addMessage);
this.getBoardData();
},
...
./src/components/Room.js
Adding Channels
...
client.on('join', function(channel) {
client.join(channel)
});
...
client.on('new-message', function(data) {
var promise = new Promise(function(resolve, reject) {
var messageData = { message: data };
requestClient.post('api/v1/messages', messageData, function(err, res, body) {
if(err) {
reject(err);
}
else {
io.sockets.to(data.channelId).emit('new-message', body);
}
})
});
});
...
./server.js
Adding Channels
https://github.com/alanbsmith/react-websocket-starter
Sharing!
Thanks!
Alan Smith
@_alanbsmith
github.com/alanbsmith
React + WebSockets
By Alan Smith
React + WebSockets
- 378