redux-saga api call delay 해서 가져오는 방법

IT쿠키·2023년 4월 16일
1

[뉴비쿠키 React]

목록 보기
10/12

api를 call 했는데 부르는 시간이 길 때 처리 방법

문제점
1. api call로 불러올 때 해당 데이터 형태의 빈값이 할당됨
2. api로 형태를 전달 후 잠시동안 data crawling 하는 시간이 길어짐
3. 이로 인한 데이터 처리 기간을 delay 시켜줘야함

해결방법을 찾아보자

일단 첫 번 째 redux-saga 구조를 만들어 보자

1. 액션명을 선언해 준다.
export const CRAWLING = "blog/CRAWLING";
export const CRAWLING_SUCESS = "blog/CRAWLING_SUCESS";
export const CRAWLING_FAIL = "blog/CRAWLING_FAIL";

2. 액션명에 맞는 api typescript를 지정해준다.
export const crwalingProduct = createAsyncAction(
  CRAWLING,
  CRAWLING_SUCESS,
  CRAWLING_FAIL
)<CrawlingState, { coupangPartners: coupangProductList }, APIError>();

2-1 CRAWLING(request 요청)일 때는 CrawlingState(형태는 객체 타입에 string[]을 요청해주는 타입을 보냄)

2-2 CRAWLING_SUCESS(response를 제대로 받았을 때) 했을 시 객체 타입에 coupangPartners에 coupangProductList라는 배열타입을 선언

2-3 CRAWLING_FAIL(request 요청 실패시) API ERROR를 나타내줌

액션명과 할당한 typescript 요청값들이 일치! 이제 saga를 본격적으로 만들어보자

function* crawlingProductSaga(
  action: ReturnType<typeof crwalingProduct.request>
  // request가 성공시 typescript return type을 활용해서 요청한 값을 유츄해냄
) {
  try {
  // 어드민 로그인시에만 활용을 해야 하기 때문에 yield select를 활용해서 해당 로그인 데이터를 가져옴
    const isLoggedIn: UserResponse = yield select(LoginStatusSelector.data);
    if (isLoggedIn) {
    
      const ItemName = action.payload;
      // 선택한 itemName 값을 action.payload로 전달
      const data: AxiosResponse<CrawlingResponse> = yield callWrapperSaga(
        blogService.coupangCrawling,
        coupangItemName
      );
      
      //callWrapperSaga 는 yield를 custom한 값! 그건 차후에 얘기할거임
      const data:axios로 받아온 response data를 
      requestId로 전달
      const reqRequestId = data.data.data.requestId;
      // 리퀘스트로 받아온 아이디값을 redux-toolkit store에 전달
      yield put(addReqRequestId({ requestId: reqRequestId }));
      // 리퀘스트 아이디를 받아온 거를 getRequestId에 전달
      const { data: resrequestId } = yield callWrapperSaga(
        blogService.getRequestId,
        reqRequestId
      );
      // yield put 해주면서 데이터를 요청 성공시 해당 값을 전달
		yield put(
          crwalingProduct.success({
            crawList: {
              isFetching: false,
              isSuccess: true,
              isError: false,
              errorMessage: "에러 없음",
              list: list,
            },
          })
    }
  } catch (response) {
    const { data, status } = response as AxiosResponse;
    yield put(crwalingProduct.failure({ data, status }));
  }
}

이게 초기 모델인데 문제가 뭐냐!
해당 list를 가져올 때 crawling 하는 시간이 길기 때문에 list:[]를 바로 요청하면 빈 배열값이 할당이됨

이제 이 문제를 해결을 해봐야함

여기서 중요한 점은 redux-saga에는 이런 걸 해결하기 위한 redux-saga yield race 라는게 있음!

race 동기적인 처리를 비동기 적으로 바꿔주는 redux-saga에 제공해줌!
하지만 그래도 이거는 실패할 경우에 나오지 않으니까 다시 이거를 반복을 시켜줘야 됨! 여기서 함수 하나를 처리해서 계속 반복을 시켜주게끔 만듬

function* waitUntilListIsReady(
  apiFunction: (
    requestId: number
  ) => Promise<AxiosResponse<ProductList>>,
  requestId: number
) {
  while (true) {
    const { data } = yield call(apiFunction, requestId);
    if (data.list.length > 0) {
      return data.list;
    }
    yield delay(5000); // 5초간 대기
  }
}

waitUntilListIsReady 말그대로 리스트가 준비되기전까지 뺑이 돌리기!
api function으로 api값을 보내고 거기서 request id를 매개변수로 전해준 다음에 data에 array값이 비었을 때 yield delay를 활용해서 다시 뺑이시켜줌

그래서 이부분을 반영해서 해당 코드를 개선!

 const { list } = yield race({
        list: callWrapperSaga(
          waitUntilListIsReady,
          blogService.getRequestId,
          reqRequestId
        ),
        timeout: delay(50000),
      });
      if (list) {
        yield put(
          crwalingProduct.success({
            crawList: {
              isFetching: false,
              isSuccess: true,
              isError: false,
              errorMessage: "에러 없음",
              list: list,
            },
          })
        );
      }

이렇게 함으로서 redux-saga에서 해당 list가 텅빈 걸 확인하고 시간을 딜레이 가능해짐! 다만 불러오는 시간이 너무 길어지면 화면에 spinner는 띄워놔야 할듯 싶다.

profile
IT 삶을 사는 쿠키

0개의 댓글