리액트 - 리덕스 미들웨어편

호돌·2020년 12월 19일
1

React(리액트)

목록 보기
13/13

리덕스 미들웨어

리덕스는 아래와 같은 흐름으로 상태를 관리하고 동작합니다.

그렇다면, 리덕스 미들웨어가 어떻게 동작하는지 흐름을 먼저 그림을 통해 보도록 하겠습니다.

리덕스 미들웨어는 왜 필요할까?🤔

기존의 리덕스는 액션이 발생하게 되면, 디스패치를 통해 스토에에게 상태 변화의 필요성을 알리게 됩니다. 하지만, 디스패치된 액션을 스토어로 전달하기 전에 처리하고 싶은 작업이 있을 수 있겠죠. 가령, 단순히 어떤 액션이 발생했는지 로그를 남길 수도 있고, 액션을 취소해버리거나, 또 다른 액션을 발생시킬 수도 있습니다.

우리가 알고 있는 리덕스는 동기적인 흐름을 통해 동작합니다. 액션 객체가 생성되고, 디스패치가 액션 발생을 스토어에게 알리면, 리듀서는 정해진 로직에 의해 액션을 처리한 후 새로운 상태값을 반환하는 과정이죠. 하지만, 동기적인 흐름만으로는 처리하기 힘든 작업들이 있습니다. 가령, 시간을 딜레이시켜 동작하게 한다던지, 외부 데이터를 요청하여 그에 따른 응답을 화면에 보여주어야 한다면 어떻게 처리해주어야 할까요?

리덕스에서는 이러한 비동기 작업을 처리하기 위한 지침을 알려주지 않고 있기 때문에 이러한 비동기 작업을 처리하는 데 있어 리덕스 미들웨어를 주로 사용합니다.

대표적인 리덕스 미들웨어

  • redux-logger : 어떤 액션이 발생했는지 로그를 남겨주는 미들웨어
  • rudux-thunk,redux-saga : 비동기 작업을 처리할 수 있게 해주는 미들웨어

✔ redux-logger

redux-logger는 앱에서 발생하는 액션 정보를 콘솔에 출력해주는 미들웨어 입니다.

리덕스 미들웨어의 동작 방식을 잠시 생각해보자면, 디스패치된 액션이 스토어로 전달되기 전에 미들웨어에서 원하는 작업을 처리한 후 스토어로 액션을 전달한다고 했습니다. 즉, redux-logger 미들웨어는 디스패치된 액션이 어떤 액션인지 확인 후, 콘솔에 로그를 남기고 액션을 스토어로 전달해주는 간단하지만, 리덕스 미들웨어의 동작 방식을 이해할 수 있는 좋은예입니다.

✔ redux-thunk, 그리고 thunk

redux-thunk는 리덕스 미들웨어에서 비동기 작업을 처리하는데 사용하는 미들웨어로 비동기 작업을 다루는 미들웨어 중에서 가장 대표적인 리덕스 미들웨어입니다.

thunk의 정의를 보면, "썽크는 주로 연산 결과가 필요할 때까지 연산을 지연시키는 용도로 사용되거나, " 라고 언급되어 있습니다.

그렇다면, 연산 결과를 지연시키는 방법은 무엇이 있을까요? 가령, 1+2를 출력하고 싶다면, 아래와 같이 코드를 작성하면 됩니다.

console.log(1 + 2);

하지만, 썽크의 정의처럼 연산 결과가 필요할 때까지 연산을 지연시키고 싶다면 아래와 같이 함수로 코드를 감싼 후, 필요할 때 함수를 호출해주면 됩니다.

const foo = () => {
  console.log(1+2);
}

그렇다면 redux-thunk는 어떻게 thunk의 개념을 적용할까요?

우리가 알고 있는 기존의 리덕스에서 액션 생성 함수는 액션을 객체 형태로 반환해주는 함수입니다. 하지만, 리덕스 썽크를 이용하면 액션 생성 함수는 객체가 아닌 함수를 반환할 수 있게 해줍니다. 즉, 객체가 아닌 함수를 반환해줌으로서 필요할 때 함수를 호출할 수 있는 썽크의 형태가 되는 것입니다.

✔ redux-saga

redux-saga의 경우엔, 액션을 모니터링하고 있다가, 특정 액션이 발생하면 이에 따라 특정 작업을 하는 방식으로 사용합니다. 여기서 특정 작업이란, 특정 자바스크립트를 실행하는 것 일수도 있고, 다른 액션을 디스패치 하는 것 일수도 있고, 현재 상태를 불러오는 것 일 수도 있습니다. 또한 redux-saga는 redux-thunk로 못하는 다양한 작업들을 처리 할 수 있습니다.

  • 비동기 작업을 할 때 기존 요청을 취소 처리 할 수 있습니다.
  • 특정 액션이 발생했을 때 이에 따라 다른 액션이 디스패치되게 하거나, 자바스크립트 코드를 실행 할 수있습니다.
  • 웹소켓을 사용하는 경우 Channel이라는 기능을 사용하여 더욱 효율적으로 코드를 관리 할 수 있습니다.
  • API 요청이 실패했을 때 재용하는 작업을 할 수 있습니다.

Generator 문법
이 문법의 핵심 기능은 함수를 작성 할 떄 함수를 특정 구간에 멈춰놓을 수도 있고, 원할 때 다시 돌아가게 할 수도 있습니다. 그리고 결과값을 여러번 반환 할 수도 있습니다.

예를 들어서 다음과 같은 함수가 있다고 가정해봅시다.

function weirdFunction() {
  return 1;
  return 2;
  return 3;
  return 4;
  return 5;
}

사실 함수에서 값을 여러번에 걸쳐서 반환하는 것은 불가능합니다. 이 함수는 호출 할 때마다 무조건 1을 반환하게 될 것입니다.

하지만, 제너레이터 함수를 사용하면 함수에서 값을 순차적으로 반환할 수 있습니다. 함수의 흐름을 도중에 멈춰놓았다가 나중에 이어서 진행 할 수도 있습니다.

제너레이터 함수를 만들 때에는 function* 이라는 키워드를 사용합니다.
제너레이터 함수를 호출했을때는 한 객체가 반환되는데요, 이를 제너레이터라고 부릅니다.
함수를 작성한 뒤에는 다음 코드를 사용해 제너레이터를 생성해보세요.

function* generatorFunction() {
    console.log('안녕하세요?');
    yield 1;
    console.log('제너레이터 함수');
    yield 2;
    console.log('function*');
    yield 3;
    return 4;
}
const generator = generatorFunction();

제너레이터 함수를 호출한다고 해서 해당 함수 안의 코드가 바로 시작되지는 않습니다. generator.next() 를 호출해야만 코드가 실행되며, yield를 한 값을 반환하고 코드의 흐름을 멈춥니다.

코드의 흐름이 멈추고 나서 generator.next() 를 다시 호출하면 흐름이 이어서 다시 시작됩니다.

제너레이터 함수의 또 다른 예시를 알아볼까요? next 를 호출 할 때 인자를 전달하여 이를 제너레이터 함수 내부에서 사용 할 수도 있습니다.

function* sumGenerator() {
    console.log('sumGenerator이 시작됐습니다.');
    let a = yield;
    console.log('a값을 받았습니다.');
    let b = yield;
    console.log('b값을 받았습니다.');
    yield a + b;
}

profile
저도 모르는데요?, 내가 몰라서 적는 글

0개의 댓글