redux-saga 中的 Promise

IT技术 reactjs promise redux redux-saga
2021-05-02 22:28:59

我在这里找到了同样的问题,但没有我正在寻找的正确答案。

我正在开发一个带有 CRUD 操作的简单应用程序。在编辑页面上,在组件被挂载 ( componentDidMount()) 后,应用程序会调度一个操作来检索特定的帖子详细信息:

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

我正在使用redux-saga并希望上述调用返回一个 Promise,以便我可以访问 API 响应。

现在,没有回调/Promise,我最终在 store 中定义了一个新状态(如post_edited)并将其连接/映射到组件中的 props 以进行编辑页面。

处理这种情况的最佳方法是什么?

4个回答

您能否提供有关您的问题的更多信息?我不确定我是否正确理解您的问题,但通常的做法是:

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);
}

有一个包完全符合 OP 的要求,即安排dispatch()可以返回Promise:@adobe/redux-saga-promise 使用它,您可以通过以下方式定义“Promise操作”创建者:

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

export const fetchPostAction = createPromiseAction('FETCH_POST')

dispatch()一个“Promise行动”将返回一个Promise:

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

传奇可能看起来像:

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);
}

apiCallToFetchPost如果apiCallToFetchPost抛出错误,它将使用由返回的值或拒绝来解决Promise它还使用您可以在减速器中访问的解决方案/拒绝来分派次要操作。该软件包提供了您必须安装才能使其工作的中间件

(免责声明,我是作者)

我是@teroneko/redux-saga-promise的开发者它最初是从@adobe/redux-saga-promise派生出来的,但现在它已经完全改造为使用 @reduxjs/toolkit 中的 createAction 来支持 TypeScript。

为了与@ronen 的例子保持联系,这里是 TypeScript 的等价物。

创建Promise操作(创建者):

import { promiseActionFactory } from '@teroneko/redux-saga-promise'
 
export const fetchPostAction = promiseActionFactory<void>().create<{ id: string }>('FETCH_POST')

发送Promise操作(来自创建者):

// promiseMiddleware is required and must be placed before sagaMiddleware!
const store = createStore(rootReducer, {}, compose(applyMiddleware(promiseMiddleware, sagaMiddleware)))
await store.dispatch(fetchPostAction({ id: 'post-id' }))

要解决/拒绝Promise操作(来自 saga):

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

import { fetchPostAction } from './actions'

function * fetchPostSaga(action: typeof fetchPostAction.types.triggerAction) {
  yield call(implementPromiseAction, action, function * () {
    const { id } = action.payload
    return yield call(apiCallToFetchPost, id)
  })
  // or for better TypeScript-support
  yield call(fetchPostAction.sagas.implement, action, function * () {
    const { id } = action.payload
    return yield call(apiCallToFetchPost, id)
  })
}

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

发生什么了?

  1. Promise操作(创建者)被创建
  2. Promise操作(来自创建者)被创建并
  3. 发送到商店。
  4. 然后 promise 操作被转换为可等待的 promise 操作,其中将其延迟版本保存到元属性中。立即返回该操作并
  5. 传递给 saga 中间件。
  6. 现在可等待的Promise操作有资格在 implementPromiseAction 中使用,除了解决或拒绝保存在可等待Promise操作的元属性中的延迟Promise之外,别无其他。

有关更多功能和高级用例,请参阅自述文件

另一种解决方案

onSubmit: (values) => {
  return new Promise((resolve, reject) => {
    dispatch(someActionCreator({ values, resolve, reject }))
  });
}

在传奇中:

function* saga() {
  while (true) {
    const { payload: { values, resolve, reject } } = yield take(TYPE)
    // use resolve() or reject() here
  }
}

参考:https : //github.com/redux-saga/redux-saga/issues/161#issuecomment-191312502