Frontend/ReactJS

리덕스 사가를 통해 리덕스에 특정작업 주입하기

findmypiece 2021. 3. 11. 18:06
728x90

관련 코드는 아래를 참고 하도록 한다.

github.com/mypiece/react-example

 

mypiece/react-example

CRA 리액트+리덕스+리덕스사가 예제. Contribute to mypiece/react-example development by creating an account on GitHub.

github.com


먼저 리덕스를 왜 사용하는지 생각해보자.

리덕스 사가는 미들웨어의 한 종류이다.

참고로 미들웨어는 아래와 같은 의미를 가지고 있다.

 

운영 체제와 응용 소프트웨어의 중간에서 조정과 중개의 역할을 수행하는 소프트웨어

 

이를 토대로 리덕스 사가를 재해석해보면 리액트와 리덕스 사이에서

무언가 추가적인 작업을 해주는 것으로 이해하면 된다.

즉, 리덕스에 의해 상태가 변경되기 전에 특정작업을 할 수 있게 해준다.

 

리액트에서는 상태변경을 통해 화면을 리렌더링 하고

이러한 상태를 관리하기 위해 리덕스를 사용한다.

때문에 화면을 리렌더링 하기 위해 리덕스를 통해 상태를 변경한다.

이렇게 변경되는 상태는 단순히 프론트엔드가 아니라

백엔드 어딘가(예를 들어 DB)에도 동기화 되어 있을 필요가 있다.

 

이를 위해 서버쪽 Api 호출같은 작업이 필요한데

이러한 작업은 리덕스를 통해 상태가 변경되기 전에 수행되어야 한다.

리덕스에서 관리되는 상태는 리액트에 종속되어 있고

웹서버가 재구동되면 결국 소멸되기 때문에

Api 호출을 통해 DB에 상태 변경 확정이 선행되어야 하고

이러한 변경이 실패할 경우 리덕스에서의 상태도 변경되어서는 안된다.

 

구현한다면 화면에서 이벤트가 발생하고 리덕스 디스패치 함수를 호출하기 전이나

리덕스 리듀서 함수 내부에서 실제 상태를 변경하기 전에 Api를 호출하는 방법이 있다.

그리고 Api 호출 결과를 받는 동안 그냥 브라우저를 멈춰놓을게 아니라

프로그래스바나 로딩스피너 같은 걸 띄워주고 싶다면

Api 호출 자체를 axios 같은 라이브러리를 통해 비동기로 수행해야 할 것이고

이를 위한 콜백함수나 Promise도 구현해야 한다.

전반적으로 생각보다 간단하지 않다는 말이다.

 

하지만 위에서 말한 미들웨어를 사용하면 이러한 중간개입을 

좀 더 수월하게 구현할 수 있게 해준다. 그게 미들웨어의 역할이기도 하다.

직접 구현해도 되지만 좀 더 획일화된 방식으로 좀 더 수월하게 

디스패치와 리듀서 수행 사이에 특정작업을 수행하기 위해 리덕스 사가를 사용한다.

이런 편의를 위해 우리는 라이브러리를 사용하고 리덕스 사가도 이런 라이브러리 중 하나이다.

 

다만 가끔 헷갈리는 사람들이 있는데 리덕스 사가로 추가하는 작업이 비동기로 수행되는 것은 아니다.

비동기 작업을 지원하기 위해 Promise 와 비슷한 기능이 제공될 뿐

리덕스 사가로 추가하는 작업은 기본은 동기이다.

 

이제 리덕스 사가로 리덕스에 Api 호출같은 비동기 작업을 어떻게 추가하는지 알아보자.

 

리덕스 사가에서는 ES6의 제너레이터 함수가 활용된다.

사실 이 문법 자체를 몰라도 리덕스 사가를 구현하는데에는 아무런 문제가 없지만

알고있다면 구현 원리를 파악하는데에는 도움이 된다.

 

제너레이터 함수는 문자그대로 발전기를 만들어주는 것으로

해당 함수를 최초 호출할 경우 함수 내부 구문이 실행되는 것이 아니라

내부 구문을 실행시킬 수 있는 제너레이터 인스턴스를 리턴하게 된다.

 

이 문법의 핵심기능은 함수를 실행할 때

함수를 특정구간에 멈춰 놓았다가 다음 호출에 이어서 실행시킬 수 있다는 것이다.

제너레이터 함수 예시는 아래와 같은데 yield 가 포함된 행에서 동작을 멈췄다가

다음 호출시 다음 구문이 이어서 진행된다.

 

제너레이터 함수에 대한 설명은 아래 포스팅을 참고하자.findmypiece.tistory.com/2

 

ES6 제너레이터 함수

redux-saga 에서는 ES6의 제너레이터 함수 문법을 사용한다. 사실 이 문법에 대해 딱히 몰라도 redux-saga를 사용법만 알면 큰 문제가 되지 않지만 원리를 알면 아주 조금은 도움이 된다. ​ 제너레이터

findmypiece.tistory.com

리덕스 사가에서는 이러한 제너레이터 함수 자체를 사가라고 부르고

이를 통해 액션을 모니터링 하거나 비동기작업 결과를 대기하도록 해서 콜백에 활용될 수 있다.

 

lib/redux/todos.js 에서 비동기처리(Api호출)이 필요한 액션을 아래와 같이 모니터링 한다.

taskLatest는 기존에 동일한 작업이 진행중이라면 취소하고

가장 마지막으로 실행된 작업만 처리되도록 한다.

이 함수의 첫번째 인자는 모니터링 할 액션타입, 두번째 인자는 수행할 작업을 함수로 정의한다.

실제 액션이 모니터링 되어 두번째 인자가 실행될 때는

액션객체가 자동으로 인자로 추가되어 실행된다.

 

모니터링 한 액션에 의해 실행될 함수를 아래와 같이 정의한다.

restCallSaga 함수는 액션타입과 axios 처리 함수를 인자로 해서

Api을 처리할 공통사가를 리턴한다.

참고로 axios는 비동기 rest호출을 지원해하는 라이브러리이다.

 

restCallSaga 함수는 아래와 같이 구현되어 있다.

restCallSaga 에서는 yield put을 통해 새로운 액션을 디스패치 한다.

yield delay를 통해 수행을 대기한다(이는 로딩스피너 확인을 위한 테스트용이다)

yield call을 통해 axios함수를 호출하면 그 결과를 대기한다.

 

결론적으로 restCallSaga는 아래 과정을 처리하는 공통함수를 리턴한다.

api 호출전 리덕스에서 관리하는 로딩상태를 true로 변경해서 화면에 로딩스피너를 띄우고

axios 호출의 결과를 대기하고 그 결과를 토대로 추가 액션을 디스패치 한다.

모든 작업이 끝나면 리덕스에서 관리하는 로딩상태를 false로 변경해서 로딩스피너를 종료한다.

 

액션 모니터링을 위해 정의한 사가는 src/index.js 에서 최초 한번은 run 되어야 한다.

이를 위해 src/lib/redux/index.js 에서 아래와 같이 사가를 통합한 루트사가를 만든다.

 

마지막으로 이렇게 통합된 액션 모니터링 사가는 src/index.js 에서 아래와 같이 run 하면 

리덕스에 미들웨어인 리덕스 사가가 추가되어 동작하게 된다.

 

728x90

'Frontend > ReactJS' 카테고리의 다른 글

props 와 state  (0) 2021.09.30
리덕스를 통한 전역상태 관리  (0) 2021.03.11
리액트에서 크롬 개발자도구 연동  (0) 2021.03.11
React 코딩컨벤션  (0) 2021.03.08
리액트 초기 설정  (2) 2021.03.08