Search code examples
javascriptreactjsreduxreact-reduxredux-saga

How can i use yield in redux-saga?


After receiving the result value of the refresh function, axiosInstace is executed before saving the accesstoken to AsyncStorage, so the updated token cannot be retrieved in axios.js through AsyncStorage.getItem. i want to save accesstoken first in refresh and get acecesstoken in axios.js and send to axiosInstace

How can I solve this problem?

this is my code

(saga.js)

    function getPostAPI(data) {
      return axiosInstace.post('/kakao/getpost', data);
    }


    function* getPost(action) {
      try {
        const result = yield call(getPostAPI, action.data);
        yield put({
          type: GETPOST_SUCCESS,
          data: result.data,
        });
      } catch (err) {
        if (err.response.data === 'jwtEx') {
          yield put({
            type: REFRESH_REQUEST,
            // data: action.data,
          });
          yield put({
            type: GETPOST_REQUEST,
            data: action.data,
          });
        } else {
          yield put({
            type: GETPOST_FAILURE,
            error: err.response.data,
          });
        }
      }
    }


    function refreshAPI() {
      return axiosInstace.post('/kakao/refresh');
    }

    function* refresh() {
      try {
        const result = yield call(refreshAPI);
        yield AsyncStorage.setItem(
          'accesstoken',
          `${result.data.accessToken}`,
          () => {
            // console.log('accesstoken 재발급 저장 완료');
          },
        );
        yield put({
          type: REFRESH_SUCCESS,
          data: result.data,
        });
      } catch (err) {
        yield put({
          type: REFRESH_FAILURE,
          error: err.response.data,
        });
      }
    }

(axios.js)

    AxiosInstance.interceptors.request.use(async (cfg) => {

      const acecesstoken = await AsyncStorage.getItem('accesstoken');
      const refreshtoken = await AsyncStorage.getItem('refreshtoken');

      if (acecesstoken) {
        cfg.headers.Authorization = `Bearer ${acecesstoken}    ${refreshtoken}`;
      }

      return cfg;
    });

    export default AxiosInstance;

Solution

  • A simple solution would be to call your refresh() generator directly:

    function* getPost(action) {
          try {
            const result = yield call(getPostAPI, action.data);
            yield put({
              type: GETPOST_SUCCESS,
              data: result.data,
            });
          } catch (err) {
            if (err.response.data === 'jwtEx') {
              yield call(refresh);
              
              // you could also redispatch the original action
              yield put(action);
            } else {
              yield put({
                type: GETPOST_FAILURE,
                error: err.response.data,
              });
            }
          }
        }
    

    Alternatively your can start a race between REFRESH_SUCCESS and REFRESH_FAILURE:

    const { success, failure } = yield race({
        success: take('REFRESH_SUCCESS'),
        failure: take('REFRESH_FAILURE'),
      });
    
    if(success) {
      // continue
    } else {
      // handle refresh failure
    }