The above reducers can actually be a whole lot shorter.
import{createStore}from'redux';
importpipelinefrom'redux-pipeline';
exportdefaultcreateStore(
pipeline(
{"ADD":(state=0,action)=> state +action.data},
{"SUBTRACT":(state=0,action)=> state -action.data}}
)
);
This is courtesy of Reducify. Head over to their documentation and check out all the ways you can make reducers. Any argument you pass to pipeline gets automatically passed to reducify.
Note! We do have one big change between the API for Reducify and Redux Pipeline - arrays will get parsed like this:
[[select, merge], reducer]
Notice we're not pulling a default value from the array! Use an earlier step in the pipeline for that.
Injected as the third argument into every reducer in the chain. <pipe> is an object with basic control flow methods.
Important! Make sure that you pass in your resulting state to any pipe methods you call. You must also return the method itself. Reducers are synchronous, we plan on keeping them that way.
End
You might want to stop the flow of the reducer chain. This is especially true if you create a generic configurable reducer but want to surpress some actions.
importpipelinefrom'redux-pipeline';
functionblockSubtract(state=0,action,pipe){
switch(action.type){
case"SUBTRACT":
// Notice we're passing state to the end method
returnpipe.end(state);
default:
return state;
}
}
// Math reducer would come from a library or something
functionmathReducer(state=0,action){
switch(action.type){
case"ADD":
return state +action.data;
case"SUBTRACT":
return state -action.data;
default:
return state;
}
}
conststore=createStore(
pipeline(
blockSubtract,
mathReducer
)
);
store.dispatch({
type:'ADD',
data:10
});
// This gets blocked
store.dispatch({
type:'SUBTRACT',
data:5
});
// State is: 10
Order matters! If you put an interrupting reducer last, it won't change anything about the final output.
Skip
skip([state, [count = 1]])
Skips the next reducer in the pipeline.
importpipelinefrom'redux-pipeline';
functionskipSubtract(state=0,action,pipe){
switch(action.type){
case"SUBTRACT":
// Notice we're passing state to the end method
returnpipe.skip(state);
default:
return state;
}
}
functionmathReducer(state=0,action){
switch(action.type){
case"SUBTRACT":
return state -action.data;
default:
return state;
}
}
// We'll get the multiplied subtraction instead
functionmathReducer2(state=0,action){
switch(action.type){
case"SUBTRACT":
return state -action.data*2;
default:
return state;
}
}
conststore=createStore(
pipeline(
skipSubtract,
mathReducer,
mathReducer2
)
);
store.dispatch({
type:'SUBTRACT',
data:5
});
// State is: -10
Mutate Action
mutateAction([mutation, [state]])
Mutates the action for the rest of the pipeline. This is not a control flow method. If you do not pass state, action will return pipe. Otherwise you must return the method result and pass in state.
importpipelinefrom'redux-pipeline';
functionincrementEnhancer(state=0,action,pipe){
switch(action.type){
case"INCREMENT":
returnpipe.mutateAction({data:2}, state);
default:
return state;
}
}
functionincrement(state=0,action){
switch(action.type){
case"INCREMENT":
return state +action.data;
default:
return state;
}
}
conststore=createStore(
pipeline(
incrementEnhancer,
increment
)
);
store.dispatch({
type:'INCREMENT'
});
// State is: 2
You can chain this together if you do not pass a state result.
importpipelinefrom'redux-pipeline';
functionincrementEnhancer(state=0,action,pipe){
switch(action.type){
case"INCREMENT":
returnpipe.mutateAction({data:2}).skip(state);
default:
return state;
}
}
functionincrementSkipThis(state=0,action){
switch(action.type){
case"INCREMENT":
throw'This reducer should not be used';
default:
return state;
}
}
functionincrement(state=0,action){
switch(action.type){
case"INCREMENT":
return state +action.data;
default:
return state;
}
}
conststore=createStore(
pipeline(
incrementEnhancer,
incrementSkipThis,
increment
)
);
store.dispatch({
type:'INCREMENT'
});
// State is: 2
API
pipeline
importpipelinefrom'redux-pipeline';
pipeline([steps ...]);
Defaults
pipeline([<Object>...]);// identical to (state = <Object>) => state
Adding that root reducer just for a default seemed kind of excessive, so if you pass in an object that doesn't match a config signature, we'll use it as a default.