
Security News
PEP 810 Proposes Explicit Lazy Imports for Python 3.15
An opt-in lazy import keyword aims to speed up Python startups, especially CLIs, without the ecosystem-wide risks that sank PEP 690.
redux-easy-models
Advanced tools
Easily define your models using standard redux libraries (redux, redux-actions, redux-thunk).
(This package is still experimental)
npm install --save redux-easy-models
In a plain vanilla redux implementation with the help of some helper libraries
like redux-actions
and redux-thunk
you might end up with something like this:
actions/timer.js
const start = createAction("TIMER_START")
//... more action creators here.
export default { start };
reducers/timer.js
import { start } from '../actions/timer';
const startReducer = handleAction(start, {
next(state, action) {...},
throw(state, action) {...}
});
Later in you containers or components you'd have to dispatch actions like this:
import { start } from '../actions/timer';
//...
dispatch(start());
While this decouples the code and keeps things simple, the amount of boilerplate
and disconnection between actions and reducers can feel painful at times. With
redux-easy-models
you could achieve the same with the following code:
models/timer.js
export default new ReduxModel({
name: timer,
actions: [ 'start' ],
reducers: {
start: (state, action) => ...
}
});
Notice how all the code for the "timer" model is in a single file. When you want to dispatch your actions, all you have to do is:
import model = '../model/timer';
//...
model.api.start();
This will automatically dispatch standard actions with standar action types. In this case the action would look like this:
{
type: "TIMER_START"
}
redux-easy-models
supports defining actions with sync and async functions, and
chaining multiple actions.
For a working demo you can go here.
import ReduxModel from 'redux-easy-models';
Define your models using a single configuration object:
const timer = {
// the name of the model. we will use this name to force
// a convention where every action will have a type with
// the name as the prefix. Can be used to combine reducers
// as well. ie:
// const reducers = combineReducers({
// [timerModel.name]: timerModel.reducer
// });
name: 'timer',
// reducer's initial state.
initialState: { started: false, count: 0, timerId: null },
// actions can either be strings or named functions.
actions: [
// in case of strings, action creators will be generated
// with redux-actions. the name of the model will be used
// as a prefix as well, ie:
// let actionCreator = createAction('TIMER_INCREASE');
'increase',
'clear',
// functions should be named and will automatically
// generate two actions, one when the execution starts,
// one in case of success or failure.
// action types will follow an upper snake convention with
// the name as the prefix, ie:
// function doSomething() {...
// will be translated to an action type of:
// TIMER_DO_SOMETHING_START
// TIMER_DO_SOMETHING_SUCCESS
// TIMER_DO_SOMETHING_FAIL
function start() {
this.clear();
return setInterval(this.increase, 1000);
},
function getTimerId() {
return this.getMyState().timerId;
},
function stop() {
let timerId = this.getTimerId();
clearInterval(timerId);
},
// functions can be async and/or return a promise,
// and the right success/fail action will be generated based
// on whether the promise is resolved/rejected.
// in case the function is not async and is sync,
// start/success/fail actions will also be generated, and
// the execution will be wrapped in a try/catch statement
async function delayStart() {
await delay();
this.start();
}
],
// reducers can be defined for actions generated by this model.
// no need to use prefix, and sufix in the case of 'Success' is
// options, so in the following list 'start' and 'startSuccess'
// are pretty much the same.
reducers: {
start: (state, action) => {
return Object.assign({}, state, { started: true, timerId: action.payload });
},
stopSuccess: (state/*, action*/) => {
return Object.assign({}, state, { started: false, timerId: null });
},
// remember that actions generated with strings in the 'actions'
// definition will not generate start/success/fail actions, so
// in this case, 'increaseSuccess' and increaseFail will not work and
// will never be called.
increase: (state/*, action*/) => {
return Object.assign({}, state, { count: state.count + 1});
},
clear: (state /*, action*/) => {
return Object.assign({}, state, { count: 0 });
}
}
};
// helper function to demonstrate async
function delay() {
return new Promise(resolve=>setTimeout(resolve, 2000));
}
// export your model
export default new ReduxModel(timer);
Once you have your model, you plug it in your redux store (redux-thunk is required).
import { createStore, applyMiddleware } from 'redux';
import createLogger from 'redux-logger';
import thunkMiddleware from 'redux-thunk';
//models
import timerModel from './models/timer';
import { combineReducers } from 'redux';
const reducers = combineReducers({
[timerModel.name]: timerModel.reducer
});
const logger = createLogger();
const store = createStore(
reducers,
applyMiddleware(...[thunkMiddleware, logger])
);
// make sure you init your model with the store!!
timerModel.init(store);
NOTICE: how the model is initialized right after the redux store is created.
Now you can consume your model from your containers or components.
import { connect } from 'react-redux'
import timerModel from '../../store/models/timer';
import HomeComponent from './HomeComponent';
const HomeContainer = connect(
(state) => {
return {
started: state.timer.started,
count: state.timer.count
};
},
() => {
return {
onStart: () => timerModel.api.start(),
onStop: () => timerModel.api.stop(),
onClear: () => timerModel.api.clear(),
onDelayStart: () => timerModel.api.delayStart()
}
}
)(HomeComponent);
export default HomeContainer;
Actions wills be generated as usual:
There are two helper methods in case you have more than one model in your application.
You can arrange your models in an array or an object:
import user from './user';
import entries from './entries';
import comments from './comments';
export {
user,
entries,
comments,
};
// could be export [ user, entries, comments]
import { createStore, applyMiddleware } from 'redux';
import createLogger from 'redux-logger';
import thunkMiddleware from 'redux-thunk';
// import the new helper functions
import { combineModelReducers, initModels } from 'redux-easy-models'
//models
import * as models from './models';
// combine all of the ReduxModel reducers
const reducers = combineModelReducers(models);
const logger = createLogger();
const store = createStore(
reducers,
applyMiddleware(...[thunkMiddleware, logger])
);
// init all the ReduxModels
initModels(models, store);
Thanks to Dan for his contributions of helper methods!
FAQs
Easily create models using standard redux architecture.
We found that redux-easy-models demonstrated a not healthy version release cadence and project activity because the last version was released a year ago. It has 1 open source maintainer collaborating on the project.
Did you know?
Socket for GitHub automatically highlights issues in each pull request and monitors the health of all your open source dependencies. Discover the contents of your packages and block harmful activity before you install or update your dependencies.
Security News
An opt-in lazy import keyword aims to speed up Python startups, especially CLIs, without the ecosystem-wide risks that sank PEP 690.
Security News
Socket CEO Feross Aboukhadijeh discusses the recent npm supply chain attacks on PodRocket, covering novel attack vectors and how developers can protect themselves.
Security News
Maintainers back GitHub’s npm security overhaul but raise concerns about CI/CD workflows, enterprise support, and token management.