Reputation: 4391
I have an action which in turn must affect many other areas of my app state. In this case, when the user selects a website from a dropdown list, it must update many other components. I'm currently doing it like so:
setSelectedWebsite (websiteId) {
// The core reason for this component
this.props.setSelectedWebsite(websiteId);
// Fetch all associated accounts
this.props.fetchAllAccounts(websiteId)
// Several other "side effect" calls here...
}
In this interest of making one component serve one purpose, this feels like a bad practice.
What is the best practice for triggering multiple actions in one call from a component?
Upvotes: 1
Views: 1354
Reputation: 9205
You could use redux-thunk.
Your component's method:
setSelectedWebsite(websiteId){
this.props.handleSetSelectedWebsite(websiteId) // this is a thunk
}
Your Redux file with action creators / thunks:
// this function is a thunk
export const handleSetSelectedWebsite = (websiteId) => (dispatch) => {
dispatch(setSelectedWebsite(websiteId))
dispatch(fetchAllAccounts(websiteId))
}
// these function are action creators (or could be other thunks if you style them the same way as the thunk above)
const setSelectedWebsite = (websiteId) => {
// your code
}
const fetchAllAccounts = (websiteId) => {
// your code
}
Upvotes: 3
Reputation: 2295
For handling complex side effects in a redux application, I would recommend looking at using Redux Sagas. I have seen its usage grow in popularity on projects large and small, and for good reason.
With sagas, in the example you have provided, you can emit a single action from a function provided through mapDispatchToProps
and let a saga take care of the rest. For example: (following example assumes flux standard actions)
//import redux connect, react, etc
class SiteSelector extends React.Component {
render() {
const id = this.props.id;
return (
<button onClick={ () => this.props.action(id)>Click Me</button>
)
}
}
const mapStateToProps = (state) => ({
id: state.websiteId
})
const mapDispatchToProps = dispatch => ({
action: (id) => dispatch(setSelectedWebsite(id))
})
export connect(mapStateToProps, mapDispatchToProps)(SiteSelector)
Now you can handle the action emitted from setSelectedWebsite
in a saga like so:
//import all saga dependencies, etc
export function* selectSite(action) {
const id = action.payload.id
yield put(Actions.selectWebsite(id))
const results = yield call(Api.fetchAllAccounts, id)
yield //do something complex with results
yield //do something else...
yield //and keep going...
}
// Our watcher Saga: spawn a new selectSite task every time the action from setSelectedWebsite is dispatched
export function* watchForSiteSelection() {
yield takeEvery('SITE_SELECTED_ACTION', selectSite)
}
For reference checkout the docs: Redux Sagas
Upvotes: 0