redux-rocketjump

Rocketjump your redux! Speed up redux-app development.
A set of tools to speed up the development of a redux based app:
- generate all you need from and for the state from a single function call, easy to extend, easy to compose.
- an out of the box way to organize redux folders by functionality instead of type.
- handy helpers to help you compose functionality.
Quick start
Install
yarn add redux redux-saga reselect redux-rocketjump
Your first rocket jump!
function loadTodosFromApi(params) {
let myHeaders = new Headers();
let config = {
method: 'GET',
headers: new Headers(),
body: params
};
return fetch('https://myawesomehost/api/posts', config)
.then(response => response.json())
}
import { rj } from 'redux-rocketjump'
export const {
actions: {
load: loadTodos,
unload: unloadTods,
},
selectors: {
getData: getTodos,
isLoading: isLoading,
getError: getTodsError,
},
reducer,
saga,
} = rj({
type: 'GET_TODOS',
state 'todos',
effect: params => loadTodosFromApi(params),
})()
import { createStore, compose, applyMiddleware, combineReducers } from 'redux'
import createSagaMiddleware from 'redux-saga'
import { makeAppsReducers, makeAppsSaga } from 'redux-rocketjump'
import * as todos from './todos'
const APPS = {
todos
}
const rootReducer = combineReducers({
...makeAppsReducers(APPS),
})
const mainSaga = makeAppsSaga(APPS)
const preloadedState = undefined
const sagaMiddleware = createSagaMiddleware()
const store = createStore(
rootReducer,
preloadedState,
compose(
applyMiddleware(sagaMiddleware),
)
)
sagaMiddleware.run(mainSaga)
export default store
Deep dive
The full documentation with many examples and detailed information is mantained at
https://inmagik.github.io/redux-rocketjump
Be sure to check it out!!
Run example
You can find an example under example, it's a simple REST todo app that uses the great json-server as fake API server.
To run it first clone the repo:
git clone git@github.com:inmagik/redux-rocketjump.git
Then run:
yarn install
yarn run-example
3.0.0
March 18, 2020
:rotating_light: Changes
-
Actions
This new major version has improved the stablity of rocketjump
ecosystem,
this version brings all the loved :heart: features from
react-rocketjump to
redux-rocketjump
.
So, for a relaxed migration the old load
and unload
action creations
still in place with the same signature when using actions
from RjObject
.
We only adjust the signature of base run
and clean
action creators:
run(params = [], meta = {}) => ({
type,
meta,
payload: {
params
}
})
clean(params = [], meta = {}) => ({
type,
meta,
payload: {
params
}
})
When we used hooks
(you can read more below),
the signature of run
and clean
is different.
Under the hood RjObject
return also buildableActions
with this different signature:
run(...params) => ({
type,
meta,
payload: {
params,
}
})
clean(...params) => ({
type,
meta,
payload: {
params,
}
})
The params passed to run
action creator are directly spread to
effect
function.
Thanks to Builder you can set the meta
with the special withMeta
method.
You can learn more about Builder
here.
Plus, a new smart action action creator updateData
has been added
to base action creators.
With updateData
action creator you can directly change the data
of your state.
updateData(newData) => ({
type,
payload: newData,
})
-
combineRjs
now returns also RjObjects
:
const {
rjs: { users: ReduxUsers, todos: ReduxTodos },
reducer,
saga,
} = combineRjs(
{
users: rj({
type,
effect,
}),
todos: rj({
type,
effect,
}),
},
{
state: 'mystatepath',
}
)
-
takeEffect
now CAN be a string here's the mapping between strings and generators (you can still use generators directly):
{
'latest': takeLatestAndCancel,
'every': takeEveryAndCancel,
'exhaust': takeExhaustAndCancel,
'groupBy': takeLatestAndCancelGroupBy,
'groupByExhaust': takeExhaustAndCancelGroupBy,
}
const RjObject = rj({
type: 'MY_TYPE',
state: 'mypath',
takeEffect: 'every',
effect: () => myApi(),
})()
-
composeReducer
now can be directly a function but can still be an array of composing reducers.
:zap: New Features
Hooks
The main features of rj
v3 are hooks.
-
useRjActions(RjObject)
This hook return an object with bound action creators of given RjObject
.
const { run, clean, updateData } = useRjActions(RjObject)
NOTE
To enable Builder onSuccess
, onFailure
and asPromise
features
you have to install the rj middleware
:
import { createStore, compose, applyMiddleware, combineReducers } from 'redux'
import createSagaMiddleware from 'redux-saga'
import {
makeAppsReducers,
rjMiddleware,
makeAppsSaga,
} from 'redux-rocketjump'
import * as todos from './todos'
const APPS = {
todos,
}
const rootReducer = combineReducers({
// HOOK for other reducers
// specialPath: specialReducer,
...makeAppsReducers(APPS),
})
const mainSaga = makeAppsSaga(APPS)
const preloadedState = undefined
const sagaMiddleware = createSagaMiddleware()
const composeEnhancers =
window.__REDUX_DEVTOOLS_EXTENSION_COMPOSE__ || compose
const store = createStore(
rootReducer,
preloadedState,
composeEnhancers(applyMiddleware(sagaMiddleware, rjMiddleware))
)
sagaMiddleware.run(mainSaga)
-
useRjState(RjObject, mapState)
This hook return the state of given RjObject
you can give a function
to transform the selected state.
const { data: todos } = useRjState(RjObject)
// or
const todos = useRjState(RjObject, (state, selectors) =>
selectors.getData(state)
)
-
useRj(RjObject, mapState)
This hooks combine useRjState
and useRjActions
and return an
array with state and actions.
const [{ data: todos }, { run: fetchTodos }] = useRj(RjObject)
-
useRunRj
This hook auto run your RjObject
according to deps
.
You can learn more here
Computed
Computed describes how to map your state you can learn more
here.
Mutations
Mutations enhance your rj with async mutations you can learn more
here.
isObjectRj
This is a tiny helper to check if a plain object is a REDUX RjObject
isObjectRj(RjObject) => Boolean