성장, 그리고 노력

부족하더라도 어제보다 더 잘해지자. 노력은 절대 배신하지 않는다.

상태관리

Redux Reducer와 Array.reduce

제이콥(JACOB) 2019. 12. 26. 17:48

Redux Reducer와 Array.reduce

Redux를 사용하기 시작하면 가장 먼저 작성해 보는 것이 리듀서(Reducer)이다. 그런데 이 리듀서에 대해 이해를 하지 않고 넘어가면, 나중에 분명 헷갈리는 경우가 생긴다. 그래서 이번에는 리듀서에 대해 조금 더 깊게 알아보려고 한다.

 

Where does the name "reducer" come from?

리듀서라는 용어는 어디서 등장했을까? 이것만 알면 리듀서에 대한 이해는 끝났다고 봐도 된다. 항상 구글 번역기에 돌려봐도 "감속기"라고만 나와서 짜증 났는데! 그런데 곰곰이 생각해 보니, 구글 번역기에 돌렸던 이유는 이 단어를 잘 몰라서이고, 알려고 하지도 않고 "리듀서"라는 단어로만 받아 드려서 그렇다. 일단 속는 셈 치고 Javascript의 Array.reduce 함수에 대해 알아보자.


Array.reduce

    // NOTE: Syntax
    arr.reduce( callback[, initialValue])

문법은 비교적 간단해 보인다. 첫번째 인자로 콜백 함수(callback), 두 번째 인자는 선택 값(optional)으로 초기값(initialValue)을 받는다.
그리고 콜백함수는 배열의 각 요소마다 실행되며, 4개의 인자를 받는다.

  • accumulator: 콜백의 반환(return) 값을 누적한다. 누적 값이라고 생각하면 되고, 콜백 함수가 첫 번째로 호출되면서, initialValue를 제공 받았다면, accumulator 값은 initialValue의 값이다. 만약 initialValue를 제공받지 못했다면, accumulator 값은 배열(arr)의 첫 번째 값과 같다.
  • currentValue: 처리할(콜백 함수가 적용될) 현재 값을 의미한다. initialValue를 제공 받았다면, currentValue 값은 배열(arr)의 첫 번째 값이다. 만약 initialValue를 제공받지 못했다면, currentValue 값은 배열(arr)의 두 번째 값과 같다.
  • currentIndex: (Optional) 처리할 현재 요소의 인덱스이다. initialValue를 제공 받았다면 0, 아니면 1부터 시작한다.
  • array: (Optional) reduce()를 호출한 배열을 의미한다.

반환 값

arr.reduce의 반환 값은 누적 계산의 결과 값이다.

사용 예제1

흔히 사용되는 패턴이다. 아래 예제는 필수 값인 accumulatorcurrentValue값만 인자로 받아 처리했다.

const strArray = ["r", "e", "d", "u", "x"];

// 화살표 함수 이용, 필수 값만 사용
const newStrArray1 = strArray.reduce((acc, currentValue) => acc + currentValue);
console.log(newStrArray1); // result: "redux"

// function 이용, 필수 값만 사용
const newStrArray2 = strArray.reduce(function(acc, currentValue) {
    return acc + currentValue;
});

console.log(newStrArray2); // result: "redux"

Redux Reducer

위에서 본 reduce를 자세히 보면 Reducer와 많이 닮아 있다.

reduce: (acc, curr) => newAccumlatedValue;
reducer: (state, action) => newSate;

다시 말해, Redux가 기본적으로 Array.reduce함수와 같다는 점을 알 수 있다. 리듀서는 각 동작이 상태에 미치는 영향을 결정할 뿐이다.

// NOTE: 사실 이 코드는 절대 Redux가 아니다. 그렇지 않은가? 예전부터 써왔던 함수일 뿐이다!
function countReducer(state = 0, action) {
    switch (action.type) {
        case "ADD_COUNT":
            return state + action.count;
        case "RESET":
            return "";
        default:
            return state;
    }
}

그렇다면 여기서 중요한 점은 무엇일까?

image


countReducer는 reduce 함수와 마찬가지로 새로운 값을 반환하며, countReducer의 상태는 변하지 않는다. 즉 상태를 불변으로 취급하며, 변경 불가능한 방식으로 상태를 업데이트함으로써 Redux는 어떤 상태 조각이 변경되었는지 알 수 있고, 앱이 렌더링 되는 방식을 최적화할 수 있는 것이다. 그리고 항상 새로운 상태를 반환하기 때문에, 동일한 인수로 호출하면 매번 동일한 출력을 얻어 예측 가능한 코드 작성이 가능하다.
그리고 이러한 Reducer의 행동을 도와주는 것이 바로 Redux 스토어(store)의 역할이다. 어떤 액션(action)이 전달되면 스토어는 리듀서를 호출하고 내부 state를 리듀서가 리턴한 값으로 바꿔주는 역할을 중간에서 해준다. 즉 액션을 기다리고, 액션을 처리하고, 상태를 업데이트하게 도와주는 것이고 이게 Redux Reducer가 작동하는 방식의 전부이다.

반응형

'상태관리' 카테고리의 다른 글

처음 접해보는 MobX - 1편  (0) 2020.02.13
[Redux & Reducer] 기초 개념 2  (0) 2019.12.10
[Redux & Reducer] 기초 개념 1  (0) 2019.12.10