1

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?

1
  • what do u mean by multiple actions?What actually it means Commented Mar 17, 2018 at 11:02

2 Answers 2

3

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
}
Sign up to request clarification or add additional context in comments.

2 Comments

Okay, so I'm already using redux-thunk. Is it best practice to put these dispatches into the action rather than calling them from the component?
@MattSaunders Yes. This way UI is separated from logic.
0

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

2 Comments

Thanks. I'm reluctant to add yet another layer to this. Is there nothing I can do with redux/redux-thunk natively?
@MattSaunders Yes thunk can do that. You would simply dispatch multiple actions in one async action creator. The syntax changes only slightly. If it's only this one component, you can also dispatch multiple actions in mapDispatchToProps. No reason to bother with sagas for this particular use case.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.