[리액트+TS] 우아한 테크러닝 3기 3주차
Web Frontend Developer

[리액트+TS] 우아한 테크러닝 3기 3주차

 

 

오늘은 우아한 테크러닝 3주차(5회차, 6회차)에서 공부했던 내용들에 대해서 정리해 보려고 한다.

다섯 번째 세션 9월 15일 화요일

5번째 수업에서는 다음과 같은 내용을 다루었다.

  • 리덕스 (Redux)
  • 커링 (Currying)
  • 몽키패치 (Monkey Patch)
  • 미들웨어 (Middleware)

다음과 같이 리듀서와 스토어를 생성한 후, 스토어의 변경이 일어날 때마다 확인할 수 있는 subscribe 메서드를 사용한다. 그리고 store의 dispatch 메서드를 이용하여 action을 실행할 수 있다.

import { createStore } from "./redux";

function reducer(state = { counter: 0 }, action) {
    switch (action.type) {
        case "INCREASE":
            return {
                ...state,
                counter: state.counter + 1,
            };
        default:
            return { ...state };
    }
}

const store = createStore(reducer);

// 구독(subscribe)
store.subscribe(() => {
    console.log(store.getState());
});

// 액션(action)
store.dispatch({ type: "INCREASE" }); // { counter: 1 }
store.dispatch({ type: "INCREASE" }); // { counter: 2 }

위의 로직들은 모두 동기적으로 진행된다. 모든 로직이 동기적이기 때문에 리듀서는 반드시 순수 함수여야 한다. 이러한 성질을 멱등성이라고 한다.

순수 함수(pure function) : 어떤 함수에 동일한 인자를 주었을 때 항상 같은 값을 리턴하는 함수
멱등성(idempotent) : 연산을 여러번 적용해도 결과가 달라지지 않는 성질

그리고 커링에 대한 설명도 간단하게 하셨다. 커링은 여러 개의 인자를 가진 함수를 호출할 경우, 파라미터의 수보다 적은 수의 파라미터를 인자로 받으면 누락된 파라미터를 인자로 받는 기법이다. 아래 예제를 보도록 하자.

const add1 = function (a, b) {
    return a + b;
};

const add2 = function (a) {
    return function (b) {
        return a + b;
    };
};

const addTen = add2(10);
console.log(addTen(20)); // 30
console.log(addTen(120)); // 130

add1 함수는 1차 함수이고 add2 함수는 2차 함수이다. add2 함수의 경우 커링을 사용하였는데, 아래 예제에서 addTen 함수처럼 사용자는 함수가 실행되는 시점에 영향을 줄 수 있다.

 

방금 리듀서로 처리하는 작업은 모두 순수한 작업이어야 한다고 했는데, 그러면 순수하지 않은 작업은 뭘까? 대표적인 예로는 비동기 API 호출 등이 있을 수 있다. 이러한 작업을 처리하기 위해 필요한 도구가 미들웨어(Middleware)이다.

미들웨어는 수도관 중간의 소독망이나 거름망 역할을 한다. 데이터가 흘러가는 중간중간 흐름(pipeline)에 거쳐가는 부분이기에 미들웨어라고 한다. 미들웨어는 연결된 순서에 따라 흐르기 때문에 항상 같은 순서대로 처리한다. 앞서 작성했던 reducer, store에 이어서 여러가지 액션들을 동기적으로 처리해주는 미들웨어를 만들어 보았다.

import { createStore } from "./redux";

function reducer(state = { counter: 0 }, action) {
    switch (action.type) {
        case "INCREASE":
            return {
                ...state,
                counter: state.counter + 1,
            };
        default:
            return { ...state };
    }
}

const store = createStore(reducer);

const middlewareOne = (store) => (dispatch) => (action) => {
    dispatch(action);
};

function middlewareTwo(store) {
    return function (dispatch) {
        return function (action) {
            dispatch(action);
        };
    };
}

function middlewareThree(store, dispatch, action) {
    dispatch(action);
}

middlewareOne(store)(store.dispatch)({ type: "INCREASE" }); // { counter: 1 }
middlewareTwo(store)(store.dispatch)({ type: "INCREASE" }); // { counter: 2 }
middlewareThree(store, store.dispatch, { type: "INCREASE" }); // { counter: 3 }

커링을 사용하게 되면 로깅 등의 작업을 처리할 때 일일이 직접 하지 않아도 된다는 장점이 있다. 그리고 몽키패치을 통해 다음과 같이 dispatch를 구현할 수도 있다. 

몽키패치(Monkey Patch): 런타임 중인 프로그램 메모리의 소스 내용을 직접 바꾸는 것이다.
let next = store.dispatch;

store.dispatch = function dispatchAndLog(action) {
    console.log("dispatching", action);
    let result = next(action);
    console.log("next state", store.getState());
    return result;
};

store.dispatch({ type: "INCREASE" });
store.dispatch({ type: "INCREASE" });

라이브러리를 사용하면서 좀 더 추가적인 기능을 사용하고 싶을 때 쓰는 도구가 플러그인(Plugin)과 미들웨어이다. 플러그인은 선택적으로 사용이 되며, 미들웨어는 데이터가 사용되는 미들웨어 소프트웨어를 전부 거쳐서 간다. 미들웨어 소프트웨어는 순차적으로 액션이 흐르기 때문에 순차적으로 순서를 보장해 주는 것이 중요하다.

여기서 커링과 몽키패칭을 통해 리덕스 logger 함수를 만드는 작업을 했었는데, 아직 이해가 완전하게 되지 않았다. 미들웨어 문서를 바탕으로 강의를 진행했는데, 다음번에 다시 한 번 제대로 봐야 할 내용인 것 같다.

 

여섯 번째 세션 9월 17일 목요일

6번째 수업에서는 다음과 같은 내용을 다루었다.

  • 웹팩 (Webpack)
  • 로더 (Loader)
  • 플러그인 (Plugin)

웹팩은 자바스크립트 모듈 번들러이다. 웹팩은 Node에서 실행되며 작성한 설정 값을 담은 객체를 읽어 처리하게 된다. Node에서 실행되기 때문에 모듈을 사용하기 위해서는 require()를 사용한다. 설정 값을 담은 객체를 생성하기 위해 config 객체를 생성하고 모듈로 내보낸다. config 속성의 entry에 기재해준 위치로부터 내부로 들어가면서 빌드한다. core-js 라이브러리는 하위호환 지원을 위한 polyfill을 위해 사용한다.

웹팩은 알아야 할 것들이 많지만, 웹팩이 그렇다고 엄청 많은 일을 해주는 것은 아니다. 그래도 사용법은 익숙해 지면 좋을 것 같다. React+TS를 사용하기 위한 웹팩 설정은 아래와 같다. 웹팩은 개인적으로 따로 정리해놓은 포스팅도 있으니 (기본, 심화) 복습해 보는 것도 좋을 것 같다.

 

로더는 마치 리덕스의 미들웨어와 같은 역할이다. entry에서 읽은 파일들은 loader로 넘어가서 각각의 로더들은 역할을 수행한다. 로더는 웹팩 설정 객체의 moudle 속성 아래 rules 배열에 작성이 된다. 로더는 컨버팅(converting), 다른 말로 트랜스파일링(transfiling)을 하는 역할을 한다. 과거에는 TS를 사용하기 위해 ts-loader를 사용했지만 현재는 babel이 지원하고 있다.

플러그인의 경우 로더보다 더 복잡하다. 플러그인은 웹팩 설정 객체의 plugins 배열에 저장한다. 플러그인은 로더가 실행된 후 실행되며 압축, 암호화 등등의 후처리를 해준다. 종류가 굉장히 많아 필요한 기능들을 제공하는 라이브러리를 찾아서 설치하면 된다.

리액트 타입스크립트 보일러플레이트를 만들어보는 예제를 다뤘었는데, 이 부분은 제대로 듣지 못해서 나중에 기회가 되면 다시 정리해 보려고 한다.

 

참고자료

  1. https://dobbit.github.io/redux/advanced/Middleware.html#%EB%AF%B8%EB%93%A4%EC%9B%A8%EC%96%B4
  2. https://github.com/textuel/Woowa_Tech_Learning_React_Typescript/blob/master/ms/week_3/Tuesday.md
  3. https://github.com/soongyu/woowa-tech-learning-react-typescript/blob/master/week03-1.md