Reputation: 1943
So I have this simple async request action creator using axios for requests and redux-thunk to dispatch actions. I want to re-use the same action creator for different requests - so each request would have its own state. I'll try to show some code and then explain more. Here is my action creator
function responseOK(response){
return {
type: RESPONSE_OK,
payload: response,
}
}
function loadingChangedStatus(isLoading) {
return {
type: IS_LOADING,
isLoading: isLoading,
}
}
function handleError(errorID){
return {
type: HANDLE_ERROR,
errorID: errorID,
}
}
export function makeRequest( URL){
return function(dispatch, getSate){
dispatch( loadingChangedStatus(true) );
axios.get( URL )
.then(function(response){
dispatch(loadingChangedStatus(false));
dispatch(responseOK(response));
})
.catch(function (response) {
dispatch(loadingChangedStatus(false));
dispatch(handleError('connection_error'));
});
}
}
And my reducer reducerRequest:
export default function(state = {isLoading:false, payload:false,errorID:false}, action){
switch (action.type) {
case IS_LOADING:
return Object.assign({}, state, {
isLoading: action.isLoading,
});
break;
case RESPONSE_OK:
return Object.assign({}, state, {
isLoading: state.isLoading,
payload: action.payload,
});
break;
case HANDLE_ERROR:
return Object.assign({}, state, {
isLoading: state.isLoading,
payload: action.payload,
errorID:action.errorID,
});
break;
default:
return state;
}
}
HERE STARTS MY PROBLEM
I combine reducers like so:
import { combineReducers } from 'redux';
import Request from "./reducerRequest";
const rootReducer = combineReducers({
// I WANT EACH OF THESE TO BE SEPARATE INSTANCE BUT USE THE SAME ACTION CREATOR / REDUCER
defaults: Request,
updates: Request,
});
export default rootReducer;
In my component:
function mapStateToProps( {defaults, updates} ){
return {defaults, updates}
}
function mapDispatchToProps( dispatch ){
return bindActionCreators({ makeRequest}, dispatch);
}
PROBLEM: I want to re-use my action creator for different requests. How can I
makeRequest('www.defaults.com')
and it ends up in defaults
makeRequest('www.updates.com')
and it ends up in updates
Now the only way I can image to solve this would be to write for every request its own action creator and own reducer - just lots of copy paste - that doesn't feel right.
How can I reuse my action creator and reducer to create 2 separate instances of defaults
and updates
in my component?
Upvotes: 2
Views: 540
Reputation: 1172
You can prefix your reducer actions per action:
export default function(namespace)
return function(state = {isLoading:false, payload:false,errorID:false}, action){
switch (action.type) {
case namespace + IS_LOADING:
return Object.assign({}, state, {
isLoading: action.isLoading,
});
break;
case namespace + RESPONSE_OK:
return Object.assign({}, state, {
isLoading: state.isLoading,
payload: action.payload,
});
break;
case namespace + HANDLE_ERROR:
return Object.assign({}, state, {
isLoading: state.isLoading,
payload: action.payload,
errorID:action.errorID,
});
break;
default:
return state;
}
}
}
and then add the namespace
function responseOK(namespace, response){
return {
type: namespace + RESPONSE_OK,
payload: response,
}
}
const rootReducer = combineReducers({
// I WANT EACH OF THESE TO BE SEPARATE INSTANCE BUT USE THE SAME ACTION CREATOR / REDUCER
defaults: Request("DEFAULTS_"),
updates: Request("UPDATES_"),
});
and then use the namespace when you call the make requests
call makeRequest('DEFAULTS_', 'www.defaults.com') and it ends up in defaults
call makeRequest('UPDATES_', 'www.updates.com') and it ends up in updates
HTH
Upvotes: 1