redux-observable-sans-boilerplate
Redux is awesome. But, boilerplate is a code smell.
This library allows you to use redux with zero boilerplate:
- ZERO constant definitions
- ZERO action definitions
- ONLY 1 dispatch definition (per http API targeted)
(and similar for websockets).
Instead of boilerplate, you should just be coding business logic.
install
npm i --save redux-observable-sans-boilerplate
use
See example
directory for a simple example of how to use library
http (json)
import { httpEpic, httpAction } from 'redux-observable-sans-boilerplate'
Setting up the middleware as per https://redux-observboilerplateable.js.org/docs/basics/SettingUpTheMiddleware.html
For our example we will be doing http request to two different backends.
const optionsGH = {
url: 'https://api.github.com',
id = 'GH',
}
const optionsCustom = {
url: 'https://mysite.url',
setHeaders: (state$, deps) => ({ Authorization: `Bearer ${action$.value.me.token}` }),
}
const rootEpic = combineReducers(httpEpic(optionsGH),httpEpic(optionsCustom))
The action creators have the signature httpAction(dispatch, id)(type, url, method = 'GET', settings = {})(body)
where:
dispatch
as provided by reaca-redux
id
is optional and should be the same value as used to create the httpEpic
type
is the front part of the type of action you will be dispatching, eg, 'GET_USERS'
:
httpEpic
will turn the dispacted action into GET_USERS_REQUEST
, GET_USERS_SUCCESS
and GET_USERS_FAILURE
type actions- the
_FAILURE
will be followed by either a HTTP_ERROR
or HTTP_UNAUTHORIZED
type action
- if
id
is defined, eg, GH
, then the following types would be changed to HTTP_GH_ERROR
or HTTP_GH_UNAUTHORIZED
- a
GET_USERS_CANCELLED
type action can be used to cancel the ongoing request
url
is the latter part of the url path; it will be appended to front piece defined in the corresponding httpEpic
method
can be GET
, POST
, PATCH
, etc.settings
is the standard options that can be passed to fetch
body
is optional; it is the JSON object, eg, from you form
To use you all you need to do is use connect(mapStateToProps, mapDispatchToProps)
from react-redux
where
const mapDispatchToProps = dispatch => ({
http: httpAction(dispatch, id),
})
which you can call from anywhere in you app, eg,
const mapDispatchToProps = (dispatch, ownProps) => ({
onSubmit: ownProps.http('GET_USERS', 'users'),
})
where your data is then passed into onSubmit(data)
.
websocket: command and query (and "event")
I created a command
and query
for websockets for convention sake, but it works perfectly fine if you just use command
.
import { socketEpics, commandAction, toAction } from 'redux-observable-sans-boilerplate'
Setting up the middleware as per https://redux-observboilerplateable.js.org/docs/basics/SettingUpTheMiddleware.html
You need to have defined a socket
object
const auth = (state$, deps) =>
({ token: state$.value.me.token, userId: state$.value.me.userId })
const rootEpic = combineReducers(...socketEpics(socket))
Note: The auth
function is completely optional.
To use you all you need to do is use connect(mapStateToProps, mapDispatchToProps)
from react-redux
where
const mapDispatchToProps = dispatch => ({
command: commandAction(dispatch),
})
which you can call from anywhere in you app, eg,
const mapDispatchToProps = (dispatch, ownProps) => ({
onSubmit: ownProps.command('updateUser'),
})
where your data is then passed into onSubmit(data)
.
Bonus: to handle events from backend you can use
socket.on(`event`, toAction(dispatch))
it expects the data object received to include a type
which will then be converted constant-case, and then dispatched as an action.
If a CommandRejected
or QueryRejected
type is received a further action of _FAILURE
type will also be emitted (based on the constant-case of the payload.type
-- idealy that would be the type of the corresponding command or query).