react-action-cable-fixed
v0.1.1
Published
Use Rails 5 ActionCable channels with React for realtime magic.
Downloads
1
Readme
Status
I'm no longer actively maintaining this package, and it may not work with newer versions of React and/or Rails. Feel free to submit PRs or open an issue if you're interested in becoming a maintainer.
ActionCable + React
Use Rails 5 ActionCable channels with React for realtime magic.
Overview
react-action-cable-fixed is a npm/bower package to bind one or more ActionCable channels to React components. This allows you to define how each individual component should respond to new messages from each channel, bringing ActionCable nicely in line with the React data model and permitting usage with a Rails API and standalone frontend React application.
Make sure to check out the example server and client (ES6 or CoffeeScript) applications to try it out for yourself.
Usage
The react-action-cable-fixed package exposes four modules: ActionCable, Cable, CableMixin, and ChannelMixin. With npm or webpack-type setups, you can require
or import
them as usual; for bower, they are set as window globals under ActionCableReact (e.g. window.ActionCableReact.ActionCable
).
First, you need to define your ActionCable channels in your application setup (like app.js
). Create your consumer:
var actionCable = ActionCable.createConsumer('ws://localhost:3000/cable');
Then, create a new Cable object with your channels:
var cable = new Cable({
ChatChannel: actionCable.subscriptions.create({channel: 'ChatChannel', room: 'example_room'}, ['newMessage'])
});
react-action-cable-fixed breaks slightly with the documented Rails method for creating a new channel here. It accepts either a channel name or a params object as the first argument, but as the second argument, it accepts an array of message types rather than an object of message handler definitions. These message types are automatically mapped to corresponding methods on React components -- for example, as we will see in a moment, a React component with the ChatChannel mixed in will automatically have the handleNewMessage
method triggered when a new message of type newMessage
is received.
Finally, when rendering your root React component, pass along the cable object in the props, e.g.:
ReactDOM.render(<MyRootComponent cable={cable} />, document.getElementById('app'))
That covers the ActionCable and Cable modules -- now for the CableMixin and ChannelMixin. The CableMixin must be included in any React component that needs to be bound to one or more ActionCable channels. It needs the React module as an argument, e.g.:
import { CableMixin } from 'react-action-cable-fixed';
import React from 'react';
module.exports = React.createClass({
mixins: [CableMixin(React)],
...
});
The ChannelMixin is used to bind one or more channels to a given component. It accepts an array of channel names as an argument, e.g.:
import { CableMixin, ChannelMixin } from 'react-action-cable-fixed';
import React from 'react';
module.exports = React.createClass({
mixins: [CableMixin(React), ChannelMixin('ChatChannel')],
...
});
The ChannelMixin gives you a handful of component methods by default:
handleConnected()
, called when the channel is initializedhandleDisconnected()
, called when the channel is disconnected or if it is rejectedhandleReceived(data)
, called when a message is received from a channel that does not match a message type defined when the channel was created (like 'newMessage' above).data
is an object.perform: (channel, action, data = {})
, used to send a message to the ActionCable server.channel
is the channel name (like 'ChatChannel' above),action
is the action to trigger on the channel (like 'newMessage'), anddata
is any other data that needs to be sent (like the contents of the message in the example below).
Additionally, if you defined any message types when initializing the channel, you automatically get those message types as component methods. For our example above, we automatically get a handleNewMessage(data)
method because we defined the 'newMessage' message type. Note that if a message type is defined, the default handleReceived(data)
method will not be called for that message.
Let's look at it all together in a simple chatroom component:
import { CableMixin, ChannelMixin } from 'react-action-cable-fixed';
import React from 'react';
module.exports = React.createClass({
mixins: [CableMixin(React), ChannelMixin('ChatChannel')],
getInitialState() {
return {
messages: []
}
},
handleConnected() {
console.log('Connected!')
},
handleDisconnected() {
console.log('Disconnected!')
},
handleNewMessage(data) {
console.log('New message: ' + data.message);
this.setState((state) => { messages: state.messages.push(data) });
},
handleSend() {
this.perform('ChatChannel', 'newMessage', { timestamp: Date.now(), message: document.getElementById('message').value });
document.getElementById('message').value = '';
},
render() {
var messages = [];
for(var i = 0; i < this.state.messages.length; i++) {
messages.push(<div key={this.state.messages[i].timestamp}>{this.state.messages[i].message}</div>)
}
return (
<div>
<div>
{messages}
</div>
<input id={'message'} />
<button onClick={this.handleSend}>Send</button>
</div>
)
}
});
The full example is available on GitHub as well as a companion server application. (Or, check it out in CoffeeScript.)
Contributing
- Fork it ( https://schneidmaster/react-action-cable-fixed/fork )
- Create your feature branch (git checkout -b my-new-feature)
- Commit your changes (git commit -am 'Add some feature')
- Push to the branch (git push origin my-new-feature)
- Create a new Pull Request
Credits
Obviously, this project is heavily indebted to the entire Rails team, and most of the code in lib/action_cable
is taken directly from Rails 5. This project also referenced fluxxor for implementation details and props binding.
License
MIT