redux-wrapper-extended
Version:
Short Cut Reducer definition.
277 lines (224 loc) • 6.33 kB
Markdown
# redux-wrapper-extended
This package gives you shortcut for redux.
#### Quick-Start
```js
import {StoreWrapper,ReducerWrapper,dispatchAction, combineReducerWrapper, uselessReducer} from 'redux-wrapper-extended';
```
#### Assumption
- Action has property **_type_**
- Action has property **_payload_**
- other than those two will be ignored
you have action object that looks like:
```js
var action = {
type:"Something",
payload //either object or value
}
```
#### Is it simplifying? YES and NO
Given you have this reducer
```js
const countReducer = (state=0,action) => {
if(action.type === "INCREMENT"){
return state + action.payload;
}
if(action.type === "DECREMENT"){
return state - action.payload;
}
if(action.type === "SETVAL"){
return action.payload;
}
return state;
}
```
By using **reducer-wrapper-extended**, you could make something like this:
```js
const countReducerWrapper =
new ReducerWrapper(0)
.addHandler("INCREMENT",(s,pl) => {
return s + pl;
})
.addHandler("DECREMENT",(s,pl) => {
return s - pl;
})
.addPropChangedHandler("SETVAL");
```
and you can use it like this:
```js
const countReducer = countReducerWrapper.getReducer();
```
```js
const storeWrapper = new StoreWrapper(
{ //combining reducers
count: countReducerWrapper.getReducer(),
detail: //some other reducer
},
{ //initial properties, nothing fancy
count:0,
detail: {
// a complex object
}
});
```
Don't worry, it's just a wrapper. you can get the actual redux store
```js
var store = storeWrapper.getStore();
store.subscribe(() => {
console.log("Store changed", store.getState());
});
```
#### Getting Fancier
```js
const detailReducerWrapper =
new ReducerWrapper()
.addPropChangedHandler("SET_NAME",(x) => x.name)
.addPropChangedHandler("SET_AGE",(x) => x.age, (state,payload) => {
if(payload<18){
return 18;
}
return payload;
})
.addPropChangedHandler("SET_PHONE",(x) => x.contacts.phone);
```
then you create a store
```js
const storeWrapper = new StoreWrapper(
{
count: countReducerWrapper.getReducer(),
detail: detailReducerWrapper.getReducer(),
},
{
count:0,
detail:{
name:"Anjar",
age:27,
contacts:{
email:"anjar.p.wicaksono@gmail.com",
phone:"81807978"
}
}
});
```
#### Combining Cascading Reducers
>Please take note that the idea the state should be as flattened as possible.
>But if you are still willing to have some level of hierarchies, here are the samples
run **detailReducerWrapper's reducer** is invoked,
then now **nameReducerWrapper's reducer** is invoked
Take note that the context of the state_ is -> detail -> name
```js
const nameReducerWrapper = new ReducerWrapper("Jon Doe") // default value
.addHandler("CHANGE_NAME",(state,payload) => {
if(!hasFunnyCharacter()){
return payload;
}
return state;
})
```
```js
const storeWrapper = new StoreWrapper(
{
detail:detailReducerWrapper.getReducer({
// override
name:nameReducerWrapper.getReducer(),
// maintain existence of 'age'
age: uselessReducer
}),
},
{
detail:{
name:"Anjar",
age:27
}
});
```
You can also do something like this
```js
const storeWrapper = new StoreWrapper(
{
detail:{
name:nameReducerWrapper.getReducer(),
// maintain existence of 'age'
age: uselessReducer,
contacts:{
// override contact in, state is relative to its context
email:emailReducerWrapper.getReducer(),
// maintain existence of 'phone'
phone:ReducerWrapper.uselessReducer,
}
},
},
{
detail:{
name:"Anjar",
age:27,
contacts:{
email:"anjar.p.wicaksono@gmail.com",
phone:"81807978"
}
}
});
```
#### Others
```js
var store = storeWrapper.getStore();
store.dispatch({type: "SET_VALUE", payload: 10});
```
equal with
```js
storeWrapper.dispatch("SET_VALUE",10);
```
this is a function pointer. the function itself checks
- if state is undefined, then return null
- else, return original state
```js
ReducerWrapper.uselessReducer
```
```js
dispatch({
type: 'ActionName',
payload: {
some:'objects'
}
})
// can be replaced with
dispatchAction(dispatch, 'ActionName', {
some:'objects'
})
```
#### Combine Reducer
You can combine reducer like this
```js
var reducers = combineReducerWrapper({
detail:parentReducerWrapper.getReducer({
// this is invoked after parentReducerWrapper's reducer
name:childReducerWrapper.getReducer(),
// this is to maintain that the state is not removed by parent reducer
age: uselessReducer,
}),
});
```
```js
var reducers = combineReducerWrapper({
detail:detailReducerWrapper.getReducer({
name:nameReducerWrapper.getReducer(),
contacts:{
email:emailReducerWrapper.getReducer(),
phone:ReducerWrapper.uselessReducer,
}
}),
});
```
#### StoreWrapper
| Function | Purpose |
| ------------- |:-------------:|
| **dispatch(type, payload)** | will call the store.dispatch with action with the same type and payload|
| **getStore()** | return original redux store |
| **getCombinedReducers()** | return combined reducers of the wrapped store |
#### ReducerWrapper
| Function | Purpose |
| ------------- |:-------------:|
| **addHandler(type, handler)** | the type is type of the action, the handler must have signature **function(state, payloadOfAction)** and return new **state** |
| **addPropChangedHandler(type, navigationProperty, handler)** | similar to **addHandler(type, handler)** but it has navigation property and the state is the context of that navigation property |
| **getReducer()** | compose the reducer |
| **static uselessReducer** | see sample above |
| **static combine(object)** | combine reducer |