Redux를 이해하자

landvibe
5 min readSep 11, 2016

--

react 생태계에는 단짝 친구처럼 항상 붙어 다니는 몇 개의 라이브러리가 있는데 그중에서도 react의 베스트 프렌드는 단연 redux다. react는 view만을 책임지는 라이브러리이므로 데이터를 어떻게 관리할 것인가가 숙제로 남는다.

역사와 전통의 MVC 패턴을 적용해서 데이터를 관리할 수도 있겠지만 페이스북은 MVC 패턴이 규모가 큰 프로그램에서는 적합하지 않다고 주장한다.

모델의 데이터는 다수의 컨트롤러와 뷰에 의해서 수정될 수 있기 때문에 큰 프로그램에서는 직관적으로 데이터의 흐름이 보이지 않는다. 그래서 페이스북이 제안하는 flux 패턴은 데이터 수정이 dispatcher 한 곳에서만 가능하도록 제약을 가한다.

flux 패턴의 구현체인 redux는 여기에 더해 store(MVC의 모델이라고 생각해도 무방하다)는 하나만 존재한다는 제약사항을 추가한다.

redux의 세 가지 원칙

공식 문서에 나와있는 세 가지 원칙이 redux를 가장 잘 설명해준다.

1. store는 오직 하나만 존재한다.

다른 말로, 전체 애플리케이션의 상태가 하나의 json object로 표현된다. json은 자바스크립트와 궁합이 잘 맞는데, 이로 인해 개발 시 편리한 점이 몇 가지 있다.

  • Undo/Redo 기능을 쉽게 구현할 수 있다. 이전 상태의 json object를 현재 상태로 덮어쓰면 그만이다.
  • 전체 상태를 저장하고 불러오기 쉽다. 마치 RPG 게임에서 저장하고 불러오기를 하듯이 하나의 json object를 어딘가에 저장하고 나중에 불러오면 그만이다.
  • 디버깅이 쉬워진다. 예를 들어, 열 번의 버튼 클릭 시 간헐적으로 에러가 난다고 가정해보자. 에러를 발생시키고 관련 로그를 모으기 위해 수도 없이 많은 버튼 클릭이 필요하다. 하지만 아홉 번의 버튼 클릭 후의 상태를 저장해서 그 시점부터 한 번의 버튼 클릭을 하고 다시 그 시점으로 돌아가서 계속 반복하면 된다. 실제로 Dan Abramov는 Time Travel 기능을 위해 redux를 만들었다.

2. store의 state는 오직 action을 통해서만 변경할 수 있다.

action은 type과 데이터를 담고 있는 json object다. 상태 변경의 경로가 단순하므로 애플리케이션의 동작을 이해하기 쉽다. 이것이 redux가 이론적 배경으로 삼고 있는 Flux의 핵심 개념이라고 할 수 있다.

3. reducer는 pure function이다.

reducer는 action과 이전 state를 입력으로 받아서 새로운 state를 리턴하는 함수이다. 같은 action과 state를 입력으로 주면 항상 같은 state를 리턴한다. pure function으로 만들기 위해서는 함수 내부에서 global 변수를 수정한다거나 랜덤 함수를 사용하면 안된다. 물론 시간 관련 함수를 사용해도 안 된다. 이로 인해 다음과 같은 장점이 있다.

  • 발생한 action을 순서대로 기억하고 있으면 언제든지 현재 상태를 만들어 낼 수 있다. 덕분에 리플레이 기능을 쉽게 구현할 수 있다.
  • 유닛테스트 코드를 작성하기가 쉽다. 정해진 입력에는 항상 예상되는 출력을 주므로 테스트 코드를 작성하는 게 즐거울 정도다.

store의 state를 수정 불가능한 변수로 만들면 성능 저하가 없을까?

물론 수정 가능한 변수가 속도면에서 더 좋지만 수정 불가능한 변수가 일반적으로 더 많은 장점을 갖고 있다. 그런데 수정 불가능한 변수를 처음으로 접하게 되면 다음과 같은 의문이 들 수 있다.

수정 불가능한 변수를 만들기 위해 매 번 새로운 메모리 공간을 할당받으면 느리지 않을까?

물론 새로운 변수를 만들기 위해 deep copy를 한다면 느리다. 그래서 수정 불가능한 변수를 지원하는 라이브러리에서는 필요한 만큼만 메모리를 할당하고 나머지는 재활용한다.

var state = {
name: 'jane',
age: 21,
family: [
{
name: 'jake',
age: 11
},
{
name: 'mike',
age: 22
},
],
};
var newState = update(state, {family: {1: {age: {$set: 30}}}});
console.log(state === newState); // false
console.log(state.family === newState.family); // false
console.log(state.family[0] === newState.family[0]); // true
console.log(state.family[1] === newState.family[1]); // false

위 예제에서 수정하려고 하는 mike의 age와 그로부터 최상위 object 사이의 모든 object는 새로운 메모리를 할당받고 나머지는 재활용된다.

모든 데이터를 redux로 관리해야 하나?

애플리케이션의 모든 상태를 redux로 관리할 필요는 없지만, 다음의 경우에 해당되는 데이터는 redux로 관리하는 게 좋다.

  • 애플리케이션의 여러 곳에서 공유되는 데이터
  • 다른 페이지를 갔다가 돌아왔을 때 그 상태를 유지할 필요가 있는 데이터

예를 들어 상품 구매 시 사용자 정보 페이지에서 결제 페이지로 갔다가 뒤로 가기를 클릭한 경우, 이전에 입력했던 사용자 정보를 유지하는 게 좋으므로 redux로 관리하면 된다. 두 가지 모두 해당되지 않는 데이터는 react에서 제공하는 컴포넌트의 state로 관리하면 된다.

정리하며

react로 개발 시 특별한 이유가 없다면 redux는 반드시 설치하는 게 좋다. redux 뿐만 아니라 create-react-app에서 기본으로 설치하는 라이브러리는 대부분 사용하는 걸 추천한다.

--

--