Search code examples
redux-saga

redux-saga and redux-toolkit confusion on how to navigate code correctly


I am a newb so lack of info there may be here. The following saga is registered

function* onboardingListener() {
  yield takeEvery(ENROLL_CRED_STATUS_REQUEST, onboarding);
}

function* onboarding(enrollFormUsername) {
    // a few lines of code that are not important 'I think'
    yield put(enrollGetContactByUsername(username));
    const { contactSuccess } = yield race({
      contactSuccess: take(ENROLL_CONTACT_FIND_SUCCESS),
      contactFailure: take(ENROLL_CONTACT_FIND_FAILURE),
    });
}

export function enrollGetContactByUsername(username) {
  const config = {
    baseURL: ENV_VARS.BASE_URL_CONTACT,
    url: '/contact/enroll',
    method: 'GET',
    params: {
      email: `${username}`,
    },
  };
  return {
    type: 'API_CALL',
    config,
    auth: false,
    spinner: true,
    successAction: ENROLL_CONTACT_FIND_SUCCESS,
    failureAction: ENROLL_CONTACT_FIND_FAILURE,
  };
}

I see ENROLL_CRED_STATUS_REQUEST wired up which I guess is the start of when onboarding will call so not sure I need to supply all that react-redux code.

Looking in redux documentation, I see code like this

const token = yield call(Api.authorize, user, password)
yield put({type: 'LOGIN_SUCCESS', token})

which makes sense to me. I do not get how my above code is calling the remote server and why call() nor fork() is being called in the above code. How exactly is the above code working? (I feel like I am really close to connecting the dots but am not quite there)


Solution

  • enrollGetContactByUsername is an action creator that creates a new action of type API_CALL which you then dispatch in onboarding saga. I suspect you have another saga somewhere running and listening on this action to handle the request. Said saga is then probably looking similar to the next snippet, except instead of Api.authorize it uses the provided config instead. So something like:

    function * apiCallSaga() {
      yield takeEvery(API_CALL, function * (action) {
        try {
          const method = axios[config.method.toLowerCase()]
          const fullUrl = config.baseURL + config.url
          const {data} = yield call(method, fullUrl, config.params)
          yield put({type: config.successAction, data})
        } catch (err) {
          yield put({type: config.failureAction, err})
        }
      }
    }
    

    To answer your second question. When you want to call a function that returns a promise, you can use either call or fork. The difference is that yielding call waits for the result - similar to await in async function - and so you can assign it to variable to get the result of the promise. On the other hand fork is non-blocking effect that instead returns immediately a "task descriptor" which is something like a promise in the saga world. You can then e.g. use the join effect to wait for the result later in the code. In 99% cases, when making api request, you want to get the result at the line of code where you are making the request and so you will use the call effect.