I'm building an application, where I need to preload people
and planet
data (it's likely that in the future more preload requirements may be added) on launch of the application. I want to have value in the store that represents the global state of the app as loaded: <boolean>
. The value would be true only then when the preload requirements people.loaded: true
and planet.loaded: true
are true. The store would look something like this:
Store
├── loaded: <Boolean>
├── people:
│ ├── loaded: <Boolean>
│ └── items: []
├── planets:
│ ├── loaded: <Boolean>
│ └── items: []
Separate action creators make the needed async requests and dispatch actions which are handled by the People
and Planets
reducers. As shown below (uses redux-thunk):
actions/index.js
import * as types from '../constants/action-types';
import {getPeople, getPlanets} from '../util/swapi';
export function loadPeople () {
return (dispatch) => {
return getPeople()
.then((people) => dispatch(addPeople(people)));
};
}
export function loadPlanets () {
return (dispatch) => {
return getPlanets()
.then((planets) => dispatch(addPeople(planets)));
};
}
export function addPeople (people) {
return {type: types.ADD_PEOPLE, people};
}
export function addPlanets (planets) {
return {type: types.ADD_PLANETS, planets};
}
export function initApp () {
return (dispatch) => {
loadPeople()(dispatch);
loadPlanets()(dispatch);
};
}
../util/swapi
handles fetching people and planet data either from LocalStorage or making a request.
initApp()
action creator calls other action creators within site.js
just before rendering to DOM as shown below:
site.js
import React from 'react';
import {render} from 'react-dom';
import Root from './containers/root';
import configureStore from './store/configure-store';
import {initApp} from './actions';
const store = configureStore();
// preload data
store.dispatch(initApp());
render(
<Root store={store} />,
document.querySelector('#root')
);
1. What are the best practices for managing global preload state of the application in Redux?
2. Is having a global loaded
state in the store necessary?
3. What would be a scalable way of checking app loaded
state in multiple React components? It doesn't seem right to include People
and Planet
state for containers that just needs to know the global app state and doesn't handle rendering of People
or Planets
. Also that would be painful to manage when the global loaded
state would be needed in multiple containers.
Quoting part of Dan's answer from Redux - multiple stores, why not? question.
Using reducer composition makes it easy to implement "dependent updates" a la waitFor in Flux by writing a reducer manually calling other reducers with additional information and in a specific order.
4. Does Dan by calling other reducers mean calling nested reducers?
First, let me correct your example.
Instead of
you can (and should) write
You don’t need to pass
dispatch
as an argument—thunk middleware takes care of this.Of course technically your code is valid, but I think my suggestion reads easier.
What you’re doing seems correct. There are no specific best practices.
No. As David notes in his answer, you’re better off storing only necessary state.
If you’re concerned about duplication, create a “selector” function and place it alongside your reducers:
Now you can import selectors from your components and use them in
mapStateToProps
function inside any component:Yes, reducer composition usually means calling nested reducers.
Please refer to my free Egghead tutorial videos on this topic:
combineReducers()
combineReducers()
from ScratchA loaded flag in your store state makes perfect sense.
However you've got too many of them. You've got
state.people.loaded
,state.planets.loaded
as well asstate.loaded
. The latter is derived from the first two. Your store really shouldn't contain derived state. Either have just the first two or just the latter.My recommendation would be to keep the first two, i.e.
state.people.loaded
andstate.planets.loaded
. Then your connected component can derive an ultimate loaded state. e.g.