-->

Promises in redux-saga

2020-07-06 08:09发布

问题:

I found the same question here, but without a proper answer I am looking for.

I am developing a simple application with CRUD operations. On the edit page, after the component gets mounted (componentDidMount()), the app dispatches an action to retrieve a specific post details:

dispatch({ type: FETCH_POST, id: 'post-id' })

I am using redux-saga and want the above call to return a Promise so that I can access the API response.

Right now, without a callback/Promise, I ended up with defining a new state in store (like post_edited) and connect/map it to props in the component for edit page.

What would be the best possible way to deal with this kind of situation?

回答1:

Could you please provide more information about your issue? I'm not sure if I understand your issue properly, but the common practice is:

API.js

function apiCallToFetchPost(id) {
  return Promise.resolve({name: 'Test});
}

postSaga.js

function* fetchPostSaga({id}) {
  try {
    const request = yield call(apiCallToFetchPost, id);
    // -> in post reducer we will save the fetched data for showing them later 
    yield put({type: FETCH_POST_SUCCESS, payload: request}); 
  } catch (error) {
    yield put({type: FETCH_POST_SUCCESS_FAILURE, error})
  }
}

export function* onBootstrap() {
  yield takeLatest(FETCH_POST, fetchPostSaga);
}


回答2:

There's a package that does exactly what the OP requested, i.e. arranges that dispatch() can return a promise: @adobe/redux-saga-promise Using it, you define a "promise action" creator via:

import { createPromiseAction } from '@adobe/redux-saga-promise'

export const fetchPostAction = createPromiseAction('FETCH_POST')

The dispatch() of a "promise action" will return a promise:

await dispatch(fetchPostAction({ id: 'post-id' }))

The saga might look like:

import { call, takeEvery }        from 'redux-saga/effects'
import { implementPromiseAction } from '@adobe/redux-saga-promise'

import { fetchPostAction } from './actions'

function * fetchPostSaga(action) {
  yield call(implementPromiseAction, action, function * () {
    const { id } = action.payload
    return yield call(apiCallToFetchPost, id)
  })
}

export function * rootSaga() {
  yield takeEvery(fetchPostAction, fetchPostSaga);
}

It will resolve the promise with the value returned by apiCallToFetchPost or reject if apiCallToFetchPost throws an error. It also dispatches secondary actions with the resolution/rejection that you can access in a reducer. The package provides middleware you have to install to make it work.

(Disclaimer, I'm the author)