Manually trigger RTK query or mutation inside a Redux Saga task

Viewed 2448

I use Redux-Saga in situations where there is complex business logic that is best separated from the component. We are adopting RTK Query and aren't able to use the endpoints manually. Yes, I am aware that Redux best practices docs suggest using Thunk when at all possible.

This particular saga task example doesn't make a great case for using Redux-Saga but there are definitely situations where the business logic is so involved/long/complex that it doesn't belong in a component and where we use saga functionality that can't be (elegantly) emulated with a simple Thunk. In this example I want to make a simple mutation (post request) on the backend:

export function* addNewCustomerTask(action: ReturnType<typeof addNewCustomer>) {
  const { name, industry, defaultIdentifierObfuscationLevel } = action.payload

  if (!name) {
    yield put(setToast({ text: 'Name can not be empty', style: ToastStyle.Error }))
  }
  else if (!industry) {
    yield put(setToast({ text: 'Industry can not be empty', style: ToastStyle.Error }))
  }
  else if (!defaultIdentifierObfuscationLevel) {
    yield put(setToast({ text: 'Default identifier obfuscation level can not be empty', style: ToastStyle.Error }))
  }
  else {
    try {
      yield call(authApiEndpoints.addCustomer.initiate, action.payload)
    }
    catch  {
      console.error('Error')
    }
  }
}

The yield call(authApiEndpoints.addCustomer.initiate, action.payload) statement doesn't do anything.

How do you perform a mutation inside of a Saga?

2 Answers

It's an action creator, you need to put it's execution result.

// start it
const promise = yield put(authApiEndpoints.addCustomer.initiate(action.payload))
// wait until finished
yield promise;

// do something with it

// unsubscribe data - will be removed from store.
promise.unsubscribe()

As for the typings:You might need to extend the types of put for typed-redux-saga something like that: (I couldn't test it, so if you have to fix something up please submit an edit to this answer) Based on https://github.com/agiledigital/typed-redux-saga/blob/591955fa5bdd73ae6f668f27a049fde21a7ffb6f/types/index.d.ts#L175-L177 and https://github.com/reduxjs/redux-thunk/blob/290acf90fa5afac5b49f286bb3d8fc51aa864ed3/src/index.d.ts#L25-L27

declare module 'typed-redux-saga' {

  export function put<TReturnType>(
    thunkAction: ThunkAction<TReturnType, TState, TExtraThunkArg, TBasicAction>,
  ): SagaGenerator<TReturnType, PutEffect<TReturnType>>;

}

If you want to use RTK-Query inside Redux-Saga and have no issue with Typescript you need to use both put and call then you can use select and RTK-query selector to access the data.

const promise = yield put(
  yield call(authApiEndpoints.addCustomer.initiate, action.payload)
);
// You need to wait for the query to be done
yield promise
    
const { data } = yield select(authApiEndpoints.addCustomer.select());
Related