Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Promises in redux-saga

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?

like image 562
Ming Soon Avatar asked Feb 17 '17 21:02

Ming Soon


People also ask

Does Redux-saga use promises?

Dispatching a promise action in a sagaThis dispatches the action and waits for the promise to resolve, returning the resolved value. Or if the promise rejects it will bubble up an error.

What is difference between takeLatest and takeEvery?

Unlike takeEvery , takeLatest allows only one fetchData task to run at any moment. And it will be the latest started task. If a previous task is still running when another fetchData task is started, the previous task will be automatically cancelled.

What are effects in Redux-saga?

In redux-saga , Sagas are implemented using Generator functions. To express the Saga logic, we yield plain JavaScript Objects from the Generator. We call those Objects Effects. An Effect is an object that contains some information to be interpreted by the middleware.

What is call and put in Redux-saga?

call() function is used to create effect description, which instructs middleware to call the promise. put() function creates an effect, which instructs middleware to dispatch an action to the store. Let's take example of how these effects work for fetching particular user data.


2 Answers

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)

like image 161
ronen Avatar answered Oct 26 '22 16:10

ronen


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);
}
like image 23
jukben Avatar answered Oct 26 '22 16:10

jukben