Reputation: 3777
I'm using redux-saga to list and update a list of items stored in a remote server. And I would like to create an item and then to list the items. That is:
import { connect } from 'react-redux'
const NewItemDialog = ({ createItem, listItems }) => {
const onAccept = () => {
// this won't work, since 'dispatch' is synchronous
await createItem('New item')
listItems()
}
// ... snip ...
}
const mapStateToProps = (state) => {
items: state.items
}
const mapDispatchToProps = (dispatch) => ({
createItem: (name: string) => dispatch(createItem(name)),
listItems: () => dispatch(listItems())
})
export default connect(mapStateToProps, mapDispatchToProps)(NewItemDialog)
What is the proper way to wait for an action to be completed?
Upvotes: 4
Views: 8031
Reputation: 3777
I've being doing some research and probably redux-thunk handles these type of situations better than redux-action. For example, you can write something like:
createItem(name).then(() => {
// redirects to the home page
// after the item has been created
history.push('/')
})
More information on this post:
https://github.com/reduxjs/redux/issues/1676#issuecomment-215413478
MORE INFO
This issue can be addressed in several ways. Here's another approach using redux-saga:
// sagas.js
// watcher function
export default function*() {
// ... snip ...
yield takeLatest(ITEM_CREATE, createItem)
yield takeLatest(ITEM_UPDATE, updateItem)
yield takeLatest(ITEM_DELETE, deleteItem)
// wait until the item has been successfully
// created, updated or deleted and **then** list the items
yield takeEvery([
ITEM_CREATE_SUCCESS,
ITEM_UPDATE_SUCCESS,
ITEM_DELETE_SUCCESS
], getItems)
}
// store.js
// ... snip ...
import sagas from './sagas'
// prepares the store and 'run' the watcher function
const sagaMiddleware = createSagaMiddleware()
const middleware = applyMiddleware(sagaMiddleware, thunk)
const composeEnhancers = (window as any).__REDUX_DEVTOOLS_EXTENSION_COMPOSE__ || compose
const store = createStore(reducers, composeEnhancers(middleware))
sagaMiddleware.run(sagas)
In any case I still prefer redux-thunk because you can dispatch an arbitrary list of 'thunks' in any specific order.
Upvotes: 0
Reputation: 6052
Typically if you need to dispatch further actions you would put all of that into a single saga. For example if the createItem
kicks off a saga that makes an api call and then needs to dispatch another action when that api call completes:
function* createItemSaga(action) {
try {
const response = yield call(makeApiCall, action.payload); // or however you call your api
// yield any actions that depend on the response succeeding
} catch(e) {
// do some error handling here - maybe return early
}
yield put(listItems());
}
You'll have to decide on how you want code organized into reusable pieces if you don't always want to call put(listItems())
after a successful createItem
call but something along these lines.
Upvotes: 2