Suppose you have a bunch of toggles and they all fire async requests. Now, how would you fire the requests? Would you store all the requests in a queue and fire only the last request since it would contain the current ui state? Or, would you fire one request and disable the component while that request is being fired?
Consider that you're using Redux (or any predictable state container) which can store the current snapshot of your ui state. Also, consider that you're using the fetch api.
If there is any other way you can handle this situation, please comment.
TIA.
I would have action creators to indicate that a request should be made... I would have sagas watching for the requests and to perform the API calls and dispatch to the store when the API call succeeds/fails.
Each toggle can be set individually without regard for other toggle requests. Your UI can check to see if a particular toggle is pending and then disable just that one toggle...
e.g.
// Actions const Actions = { REQUEST: 'REQUEST', SUCCESS: 'SUCCESS', FAILURE: 'FAILURE' }; // Action Creators const request = id => ({ type: Actions.REQUEST, payload: id }); const success = id => ({ type: Actions.SUCCESS, payload: null, meta: { id } }); const failure = (id, err) => ({ type: Actions.SUCCESS, payload: err, error: true, meta: { id } }); // Sagas function* requestSaga() { yield takeEvery(Actions.REQUEST, function*(action) { const { id } = action.payload; try { yield call(yourApiPostMethod, `/api/toggle/${id}`); } catch (err) { yield put(failure(id, err)); return; } yield put(success(id)); }); } // Reducer const reducer = (state = {}, action) => { switch (action.type) { case Actions.REQUEST: return { ...state, pending: [ ...state.pending, action.payload ], }; case Actions.SUCCESS: { const { id } = action.meta; const { errors, pending } = state; const newErrors = { ...errors }; delete newErrors[id]; const i = pending.indexOf(id); return { ...state, pending: pending.splice(i, 1), errors: newErrors, }; } case Actions.FAILURE: { const { id } = action.meta; const { errors, pending } = state; const i = pending.indexOf(id); return { ...state, pending: pending.splice(i, 1), errors: { ...errors, [id]: action.payload }, }; } } return state; }; // Components const Child = ({ toggle, pending, label }) => <div onClick={ toggle } disabled={ pending }>{ label }</div> ; const ParentComponent = ({ toggle, pending, items, ...otherProps }) => <div> {items.map(i => <Child key={ i.id } toggle={ toggle(i.id) } label={ i.label } pending={ pending(i.id) } /> )} </div> ; const mapStateToParentProps = state => ({ pending: id => state.pending.indexOf(id) >= 0, }); const mapDispatchToParentProps = dispatch => ({ toggle: id => () => dispatch(request(id)) }); const Parent = connect( mapStateToParentProps, mapDispatchToParentProps )(ParentComponent);I have a bunch of redux-saga posts planned over the next few weeks on my blog. Check it out if you'd like more of this. https://decembersoft.com/posts/tag/redux-saga/