Search code examples
redux-sagaredux-toolkitrtk-query

Manually trigger RTK query or mutation inside a Redux Saga task


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?


Solution

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