Using WebSockets with Reflux and React
Using WebSockets, React and Reflux together can be a beautiful thing, but the intial setup can be a bit of a pain. The below examples attempt to offer one (arguably enjoyable) way to use these tools together.
This trifect works well if you think of things like so:
this.state
in react should instead live within stores. Stores can listen to other stores as well as to events being fired.props
instead of listening to stores everywhere.var Reflux = require('reflux');
module.exports = Reflux.createActions([
'delete',
// 'update', 'flag', 'report', 'search', etc...
]);
var _ = require('lodash');
var React = require('react');
var UserActions = require('./UserActions');
module.exports = React.createClass({
delete(e) {
e.preventDefault();
UserActions.delete(this.props.user.id);
},
render() {
return (
<tr>
<td>{this.props.user.name}</td>
<td><button onClick={this.delete}>Delete</button></td>
</tr>
);
}
});
var _ = require('lodash');
var React = require('react');
var Reflux = require('reflux');
var UserStore = require('./UserStore');
module.exports = React.createClass({
mixins: [
Reflux.connect(UserStore, 'userStore'),
],
render() {
var store = this.state.userStore;
if (store.loading) {
return <div className='alert alert-info'>Loading...</div>;
}
if (store.errorMessage) {
return <div className='alert alert-danger'>{store.errorMessage}</div>;
}
var users = _.map(store.users, function (user) {
return <UserItem user={user} key={user.id} />;
});
return (
<table>
<thead>
<tr>
<th>Name</th>
<th>Actions</th>
</tr>
</thead>
<tbody>
{users}
</tbody>
</table>
);
}
});
var _ = require('lodash');
var Reflux = require('reflux');
var io = require('socket.io-client');
var socket = io();
var UserActions = require('./UserActions');
var initialState = {
loading: false,
errorMessage: '',
users: [],
};
module.exports = Reflux.createStore({
listenables: [UserActions],
init() {
socket.on('connect', () => {
this.fetchUsers();
});
},
getInitialState() {
return this.state = initialState;
},
fetchUsers() {
this.state.errorMessage = '';
this.state.loading = true;
socket.emit('users:all', this.updateUsers.bind(this));
},
updateUsers(err, users) {
this.state.errorMessage = '';
this.state.loading = false;
if (err) {
console.error('Error updating users:', err);
this.state.errorMessage = err;
this.trigger(this.state);
return;
}
this.state.users = users;
this.trigger(this.state);
},
onDelete(userID) {
var user = _.find(this.state.users, { id: userID });
// Indicate the user is being updated.
this.state.errorMessage = '';
this.state.loading = true;
this.trigger(this.state);
socket.emit(
'users:delete',
userID,
function (err) {
// The callback has been fired so indicate the request has finished.
user.loading = false;
if (err) {
console.error('Error deleting user:', err);
this.state.errorMessage = err;
this.trigger(this.state);
return;
}
// TODO: Delete the user from the list of users here...
this.trigger(this.state);
}.bind(this)
);
},
});