리덕스 사가 비동기 호출 시 effects 중 call 을 사용하는 이유

Felix Yi·2020년 3월 17일
0

상황과 필요

리액트를 다루는 기술을 중 리덕스 사가 구현하는 부분 중 아래와 같이 call 을 설명하는 부분이 있다.

// call을 사용하면 Promise 를 반환하는 함수를 호출하고, 기다릴 수 있습니다.
const post = yield call(api.getPost, action.payload)

근데 call 은 원래 context 바인딩 해주는 것 뿐이고. async/await 처럼 호출하고 기다리게 해준다니?

이터레이터.next() 전까지는 아예 결과 = yield 표현식 자체가 실행이 안 되고, next() 한 후에는 어차피 다음 yield 라인이 실행 안될 텐데 무슨 call 로 비동 기 요청 후 대기를 때리나????

결론

redux-saga/effects 의 call 은

  • 리덕스 사가가 실행해야할 행위를 설명하는 순수객체를 생성해서 yield 의 결과로 리턴하며
  • 리덕스 사가는 그렇게 생성된 (비동기 요청)행위 설명 객체를 가지고 실제 실행을 담당하며
  • 리덕스 사가는 그 행위가 resolve 될 때까지 기다린다.

즉, 맞다.

리덕스 액션객체를 왜 만드냐는 생각 해봤다. 결국 리듀서에게 실행을 위힘하기 위해서, 설명서 같은 걸 준다고 생각하면 될 거 같다.

내가 너를 뒤져서 일일히 호출하는 것이 아닌, 나는 너만 호출하고 대신 할 일을 넘기는 것.

유명한... 호주머니 뒤져서 돈 꺼내가는 캐셔일화가 기억나네. 돈 꺼내달라 요청해서 그 행위를 구매자에게 위임하면 되는 거.

필요 채우기

검색해서 서술적 이펙트문서를 찾음.

리덕스사가의 effects 중 call 은 자바스크립트 call 과 하는 짓은 같은데, effects 객체를 리턴한다.

구지 안써도 되는 거였음. 다만 테스트 할 때 필요하다고 문서에 적혀있다.

function* 비동기제너레이터() {
  const 프로미스결과 = yield Api.fetch('주소')
}

이후 value 로 값을 보면 되는데, assert 테스트를 한다고 하면 구체적인 결과를 넣어야 하고, api 변경이 일어나서 필드가 빠졌다 넣어졌다 하면 그 때마다 그 실제 응답 객체 넣어서 붙여 줘야함.

const 이터레이터 = 비동기제너레이터()
assert.deepEqual(이터레이터.next().value, ??) // 

프론트에서 비동기 요청까지만 책임을 지니까. 요청 주소가 올바른지 등만 점검하면 되고 그 응답 결과에 대해서는 테스트 할 필요가 없다.

그래서 리덕스사가 effecs call 을 쓰면

import { call } from 'redux-saga/effects'

function* 비동기제너레이터() {
  const products = yield call(Api.fetch, '/products')
  // ...
}

yield 결과로 아래 모양의 객체만 생성된다.

{
  CALL: {
    fn: Api.fetch,
    args: ['./products']
  }
}

이게 무슨 짓이냐? 이 객체는 단지 설명할 뿐이고. 추후에 이터레이터.next() 호출로 실행이 될 때, 리덕스 사가가 저 객체를 가지고 실행한다.

액션 객체 만들어서 리듀서한테 리턴하면 리듀서에서 실제 실행을 담당하는 것처럼. 예도 그리한다고 설명이 되어있다.(코드는 안 까봤음)

그리고 리덕스 사가가 call 로 생성된 객체를 가지고 비동기 요청을 실행하면, resolve 될 때까지 기다렸다가 resolve 되면 재가동 시킴.

순수 (비동기 요청)행위 설명 객체 덕분에 이제 테스트가 좀 쉬워졌다.

// call 로 생성된 행위객체를 비교검증한다.
assert.deepEqual(
  이터레이터.next().value,
  call(Api.fetch, '/products'),
  "fetchProducts should yield an Effect call(Api.fetch, './products')"
)
profile
다른 누구와도 같은 시장 육체 노동자

0개의 댓글