redux-cablecar
v5.0.7
Published
Rails 6 ActionCable <-> Redux middleware
Downloads
2,803
Maintainers
Readme
CableCar (redux-cablecar)
Redux CableCar is Redux middleware connecting Redux actions to Rails Action Cable. It uses Action Cable's websocket connection to automatically pass specific redux actions from the client to the server, and converts messages coming from the server into client-side redux actions.
Installation
yarn add redux-cablecar
Usage
Step 1
Create cablecar route and middleware
import { createStore, applyMiddleware } from '@reduxjs/toolkit'
import { createCableCarRoute } from 'redux-cablecar'
const cableCarRoute = createCableCarRoute()
const cableCarMiddleware = cableCarRoute.createMiddleware()
Step 2
Add middleware to list of redux middleware
const middlewares = [cableCarMiddleware]
const store = createStore(reducer, applyMiddleware(middlewares))
Step 3
Initialize the cablecar to the redux store with the Rails ActionCable channel
const options = {
params: { room: 'game' },
permittedActions: ['SERVER', 'RAILS', /.+ALSO_TO_SERVER$/]
}
const cableCar = cableCarRoute.connect(store, 'MainChannel', options)
Server Side Example
class MainChannel < ApplicationCable::Channel
def subscribed
stream_from "#{params[:room]}"
end
end
CableCarRoute
createCableCarRoute(options)
provider
- custom provider (not necessary)webSocketURL
- custom WS url (not necessary)
createCableCarRoute({
provider: myCustomProvider,
webSocketURL: 'ws://custom:8080'
})
#connect(store, channel, options)
store (Store, required)
Redux store object.
channel (string, required)
Name of the ActionCable channel (ie. 'ChatChannel').
options (object)
params
- object sent to ActionCable channel (ie.params[:room]
)permittedActions
- string, RegExp, (string|RegExp)[], function - filters actions that get sent to the servermatchChannel
- boolean optional shortcut for using multiple channelssilent
- boolean creates one-way communication to Rails (filtered client actions get sent to the server, but no server messages will dispatch redux actions)
options - ActionCable Callbacks
initialized
connected
disconnected
rejected
Redux Actions
Permitted Actions
Actions must be permitted to be sent to Rails.
By default this is any action of with a type prefix RAILS
.
Example: { type: 'RAILS_ACTION' }
It can be customized with the permittedActions
option.
String (prefix)
cableCarRoute.connect(store, 'channelName', { permittedActions: 'my_prefix/' })
This will match my_prefix/anyaction
.
RegExp
cableCarRoute.connect(store, 'channelName', { permittedActions: /suffix$/ })
List of strings OR regular expressions
cableCarRoute.connect(store, 'channelName', { permittedActions: ['prefix', /orsuffix$/] })
Custom Function
cableCarRoute.connect(store, 'channelName', {
permittedActions: action => action.server === true
})
Match Channel
A shortcut for a use case with multiple channels
cableCarRoute.connect(store, 'channelOne', {
matchChannel: true
})
cableCarRoute.connect(store, 'channelTwo', {
matchChannel: true
})
This is the equivalent of writing:
cableCarRoute.connect(store, 'channelOne', {
permittedActions: (action) => action.meta.channel === 'channelOne'
})
cableCarRoute.connect(store, 'channelTwo', {
permittedActions: (action) => action.meta.channel === 'channelTwo'
})
CableCar Object
The CableCar object has the following other functions:
#destroy
Disconnects and destroys cablecar. This is useful if changing channels/params.
const cableCarRoute = createCableCarRoute()
const cableCar = cableCarRoute.connect(store, 'GameChannel', { params: { room: 1 }})
cableCar.destroy()
cableCarRoute.connect(store, 'GameChannel', { params: { room: 2 }})
#pause
Pauses the cablecar.
#resume
Resumes the cablecar.
#perform(method, payload)
Calls a Rails method directly. (See Rails documentation for more)
Example:
cableCar.perform('activate_something', { data: ... })
class ChatChannel < ApplicationCable::Channel
def subscribed
stream_from "chat"
end
def activate_something(payload)
...
end
end
(See ActionCable documentation for more)
#send(action)
Sends a direct message to Rails (outside of the Redux middleware chain)
Optimistic Actions
Redux actions matching the permittedActions
criteria get sent to the Rails server.
However if isOptimistic: true
is in the action meta property, then the action will be sent to both the Rails Server, as well as being propagated thru the rest of the Redux middlewares. These actions are considered 'optimistic' updates, since when news comes back from the server it may conflict with changes that have already been made on the client.
Example:
{ type: 'RAILS_ACTION_ALSO_REDUX_SAME_TIME', meta: { isOptimistic: true }}
Dropped Actions
Dropped actions are permitted actions that cannot be sent with the ActionCable subscription, because the connection has not yet been initialized or connected, or has been disconnected.
Optimistic on Fail
Dropped actions are usually a sign of a timing issue that needs to be resolved, but if necessary a meta property isOptimisticOnFail
can be added to an action. These actions will be passed to redux only if dropped.
{ type: 'RAILS_SERVER_OR_REDUX_IF_DROPPED', meta: { isOptimisticOnFail: true }}
Multiple Stores, Channels, and WebSocket URLs
While unlikely scenarios, redux-cablecar
does support multiple channels, Redux stores, and even websocket connections.
Every Redux store should have a unique cable car route, with a unique middleware object created.
Only one consumer is maintained per unique webSocketURL, so separate routes may use the same webSocketURL.
Development
Clone and run npm install
.
Link the package locally with npm link
and use npm run watch
to update package changes.
Pull requests welcome.
Tests
npm test
See Also
License
MIT