I want to create a Redux store that has this shape:
store = {
loaded: Boolean,
loading: Boolean,
view: Object, // uses combineReducers
layers: Object // uses combineReducers
}
So far, my root reducer looks like this:
rootReducer.js
import view from './view';
import layers from './layers';
const initialState = {
loaded: false,
loading: false,
};
function loadState(state = initialState, action = {}) {
switch (action.type) {
case 'LOADED':
return {
...state,
loaded: true,
loading: false,
};
case 'LOADING':
return {
...state,
loaded: false,
loading: true,
};
default:
return state;
}
}
export default combineReducers({
view,
layers,
// hmmmm, putting loadState here would give me a loadState object property,
// not loose 'loaded' and 'loading' properties
});
How do I also have these "loose" properties like loaded
and loading
alongside them?
Sometimes I find writing individual reducers for a few simple properties to be obnoxious overhead, so I have a combineReducersWithRoot
utility I use sometimes.
export function combineReducersWithRoot(rootReducer, reducers) {
return (state, action) => {
// Ensure the root state object is a new object; otherwise
// React may not re-render.
let newState = {...rootReducer(state, action)};
Object.keys(reducers).forEach(domain => {
let obj = state ? state[domain] : undefined;
newState[domain] = reducers[domain](obj, action);
});
return newState;
};
}
Now, given a state structure something like this:
{
loading: bool
loaded: bool
data: {
filter: string
arr: object[]
}
}
You can do this:
function rootReducer(state = {loading: false, loaded: false}, action) {
switch(action.type) {
case STARTED_LOADING:
return {...state, loading: true, loaded: false};
case FINISHED_LOADING:
return {...state, loading: false, loaded: true};
default:
return state;
}
}
function dataReducer(state = {filter: '', arr: []}, action) {
switch (action.type) {
case SET_FILTER:
return {...state, filter: action.value};
case SET_DATA:
return {...state, arr: action.arr};
default:
return state;
}
}
export default combineReducersWithRoot(rootReducer, {data: dataReducer});
@PhiNguyen is right, I need to turn these loaded/loading properties into their own reducers!
import { LOADED, LOADING } from '../ActionTypes';
export function loaded(state = false, action = {}) {
switch (action.type) {
case LOADED:
return true;
case LOADING:
return false;
default:
return state;
}
}
export function loading(state = false, action = {}) {
switch (action.type) {
case LOADED:
return false;
case LOADING:
return true;
default:
return state;
}
}
rootReducer.js
import { loaded, loading } from './load';
import view from './view';
import layers from './layers';
export default combineReducers({
loaded,
loading,
view,
layers
});
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With