Reputation: 14219
Imagine a car configuration app. Here is an example state tree:
{
// selections
modelYear,
modelId,
transmissionId,
// options
modelYears: [],
models: [],
transmissions: [],
accessories: []
}
When the app starts it would load some initial data. Then you would start by selecting a model year to populate the list of models, then select a model, then a transmission, accessories, etc. Each piece of data relies on the previous selection in a hierarchical manner. An example sequence of events on page load would be the following:
When the user changes a selection of any piece of the data, new data lower in the hierarchy has to be retrieved and the UI has to be repopulated.
Here are some snippets of what I have written:
actions
export function getModelYears() {
return dispatch => {
vehiclesApi.getModelYears(years => {
dispatch(receiveModelYears(years))
})
}
}
export function getModels(year) {
return dispatch => {
vehiclesApi.getModels(year, models => {
dispatch(receiveModels(models))
})
}
}
function receiveModelYears(years) {
return {
type: types.RECEIVE_MODEL_YEARS,
years: years
}
}
function receiveModels(models) {
return {
type: types.RECEIVE_MODELS,
models: models
}
}
export function selectModelYear(year) {
return {
type: types.SELECT_MODEL_YEAR,
year
}
}
reducers
function vehicle(state = {}, action) {
switch (action.type) {
case SELECT_MODEL_YEAR:
return Object.assign({}, state, {
modelYear: action.year
})
case SELECT_MODEL:
return Object.assign({}, state, {
modelId: action.modelId
})
default:
return state
}
}
function modelYears(state = [], action) {
switch (action.type) {
case RECEIVE_MODEL_YEARS:
return state.concat(action.years)
default:
return state
}
}
function models(state = [], action) {
switch (action.type) {
case RECEIVE_MODELS:
return state.concat(action.models)
default:
return state
}
}
I'm not sure how to structure my reducers & actions to handle the default selections and request new data after selections are made. The manual actions are easy (user clicks, dispatch action). But how do I manually dispatch getModels(year)
after selecting the first year by default?
Here is the best way I can describe the flow in pseudo code:
store.dispatch(getModelYears())
store.subscribe(() => {
// if model years received
store.dispatch(selectModelYear(store.getState().modelYears[0]))
// if modelYear selected
store.dispatch(getModels(store.getState().modelYear))
// if models received
store.dispatch(selectModel(store.getState().models[0].id))
// if model selected
store.dispatch(getTransmissions(store.getState().modelId))
store.dispatch(getAccessories(store.getState().modelId))
// ...etc
})
I would like to test this system agnostic of any UI framework since I'm building it as a proof of concept for managing my client state and may not be able to use React.
Upvotes: 1
Views: 1107
Reputation: 22389
If I understood your requirements correctly, you're looking for a way to respond to a state change by triggering another action. For example, whenever store.modelYear
changes, you need to trigger the RECEIVE_MODELS
action.
The subscribe method looks right for the job. If you want a more structured design, there are patterns built on top of subscribe
, for example actors: http://jamesknelson.com/join-the-dark-side-of-the-flux-responding-to-actions-with-actors/
Upvotes: 2