Unlimited Plugins, WordPress themes, videos & courses! Unlimited asset downloads! From $16.50/m
Advertisement
  1. Code
  2. Redux
Code

Redux로 시작하기: 왜 Redux인가? 

by
Difficulty:BeginnerLength:LongLanguages:

Korean (한국어) translation by Jin Ah Chon (you can also view the original English article)

여러분은 React를 공부할 때 Redux가 얼마나 훌륭한지, 그리고 한 번 써보라고 권유하는 사람들의 얘기를 거의 항상 듣게 될 것입니다. React 생태계는 빠르게 성장하는 중이고, React와 연결 가능한 flow와 redux, middlewares, mobx 등 라이브러리가 많이 있습니다.

React는 배우기가 쉽습니다. 그러나 React 생태계 전체를 능숙하게 알게되는 데는 시간이 걸립니다. 이번 튜토리얼에서는 React 생태계의 통합 컴포넌트 중 하나인 Redux를 소개하겠습니다.

비(非) Redux 기본 용어

다음은 여러분이 아마 잘 알지 못하지만, Redux 자체에서 특이하지 않게 흔히 사용되는 용어 중의 일부입니다. 이 섹션을 대충 훑어보고 무언가 이해되지 않을 때는 언제라도 여기로 다시 돌아오세요.

순수함수 

순수함수는 다음과 같이 충족해야 할 두 가지 추가적인 제약조건을 가진 전형적인 함수입니다.

  1. 한 세트의 input(입력값)이 있다는 가정 하에 함수는 늘 같은 output(출력값)을 반환해야 합니다.
  2. 부작용을 낳지 않습니다. 

두 개의 숫자를 더한 값을 반환하는 순수함수가 있다고 예를 들어 보겠습니다.

순수함수는 예상 가능한 output을 내고 결정성(deterministic)을 갖습니다. 반환 값을 계산하는 것만 수행할 때 함수는 비순수해집니다.

한 예로 아래의 덧셈 함수는 output(출력값)을 계산하는 데 전역state를 사용했습니다. 더구나 그 함수는 그 값을 콘솔에 로그(logs)로 출력했으며, 이는 부작용으로 간주됩니다.

관찰 가능한 부작용

“관찰 가능한 부작용”이란 외부 세계에서 사용된 함수에 의해 생긴 인터랙션을 칭하는 고급 용어입니다. 어떤 함수가 그 함수 밖에 있는 변수에 값을 쓰려 하거나 외부 메서드를 호출하려 한다면, 이러한 것들을 틀림없이 부작용이라 부를 수 있습니다.

그럼에도 불구하고 순수함수가 또 다른 순수함수를 호출한다면 그 함수는 순수함수로 취급됩니다. 다음은 일반적인 부작용들 중의 일부입니다.

  • API 호출하기
  • 콘솔로 로그를 찍거나 데이터를 프린트하기
  • 데이터를 변형하기
  • DOM 조작하기
  • 현재 시간을 검색하기

Container 컴포넌트와 Presentational 컴포넌트

React 애플리케이션으로 작업하는 동안 컴포넌트 구조를 두 가지로 분리하는 것이 유용합니다.  여러분은 컴포넌트들을 크게 두 가지 카테고리로 분류할 수 있습니다. container 컴포넌트와 presentational 컴포넌트로 말입니다. 데이터를 처리하는(smart) 컴포넌트와 그렇지 않는(dumb) 컴포넌트로도 보편적으로 알려져 있습니다.

container 컴포넌트는 어떻게 동작하는지와 관련이 있으며, 그와 달리 presentational 컴포넌트는 어떻게 보이는지와 관련이 있습니다. 저는 개념을 더 잘 이해시키려고 다른 튜토리얼에서 React에서의 Container 컴포넌트 대 Presentational 컴포넌트을 다루었습니다.

변하는(mutable) 객체 대 변하지 않는(immutable) 객체

변하는 객체는 다음과 같이 정의될 수 있습니다.

변하는 객체는 해당 state가 만들어 진 후에 수정 가능한 객체입니다.

변하지 않음(immutability)은 정확히 그 반대이고, 변하지 않는 객체는 해당 state가 생성되고 나서 수정 불가능한 객체입니다. 자바스크립트에서 문자형(string)과 숫자형(number)은 변하지 않지만, 객체(object)와 배열(array)는 변합니다. 아래의 예에서 그 차이를 잘 보여줍니다.

객체를 변하지 않게 하려면 새로운 메서드나 새로운 스프레드 연산자 전체를 생성하는 Object.assign 메서드를 사용하세요.

Redux란?

공식 페이지에서 Redux를 다음과 같이 정의합니다.

Redux는 자바스크립트 애플리케이션에서 흔히 쓰이는 state container입니다.

앞의 정의가 Redux를 정확히 설명하고 있으나, 처음에 Redux의 좀 더 큰 그림을 본다면 쉽게 잊어버립니다. 여러분이 맞춰야 할 움직이는 조각들이 너무 많습니다. 그럼에도 일단 작업해 보면, 장담하건데 Redux를 좋아하게 될 겁니다.

Redux는 React 뿐만 아니라 어떠한 자바스크립트 라이브러리와도 연결할 수 있는 state 관리 라이브러리입니다. 그래도React의 기능 측면에서 그 본질로 인해 React와 가장 잘 동작하지요. 더 잘 이해해보도록 state를 살펴 봅시다.

Any change in the state rerenders the component and any user interaction updates the state

보시다시피 컴포넌트의 state는 무엇을 렌더링하고 어떻게 동작할지를 결정합니다. 애플리케이션에는 초기 state가 있고, 사용자의 인터랙션으로 state를 업데이트하는 액션이 일어납니다. state가 업데이트될 때 페이지가 렌더링되죠. 

React를 이용하면, 각각의 컴포넌트에 컴포넌트 안에서 접근 가능한 로컬 state가 있습니다. 그렇지 않으면 props로써 자식 컴포넌트에 넘겨줄 수 있습니다. 

  1. UI state와 과도기적(transitionary) 데이터. 네비게이션 메뉴용 UI 요소들 목록이나 제어되는 컴포넌트에 있는 form input이 해당됩니다. 
  2. 서버에서 페치(fetch)된 데이터 같은 애플리케이션 state, 사용자의 로그인 state 등

컴포넌트의 state에 애플리케이션 데이터를 저장하는 것은 여러분에게 한두 가지 컴포넌트가 들어간 기본적인 React 애플리케이션이 있을 때 괜찮습니다. 

React Project with a few components
기본 애플리케이션의 컴포넌트 계층구조

하지만 대다수의 실제 사용되는 앱들에는 피쳐(features)와 컴포넌트들이 훨씬 더 많습니다. 컴포넌트의 계층구조에서 층수가 늘어날 때 state 관리는 다루기 어려워집니다.

Component hierarchy of a chat application using React
중간 규모의 애플리케이션 스케치 

Redux를 왜 사용해야 할까요? 

여러분이 React로 작업하는 동안 이해할지 모를 매우 그럴싸한 시나리오가 여기 있습니다.

  1. 여러분은 중간 규모의 애플리케이션을 만들고 있으며, 컴포넌트를 데이터를 처리하는 컴포넌트와 그렇지 않은 컴포넌트로 깔끔하게 나누었습니다. 
  2. 데이터를 처리하는 컴포넌트는 state를 처리하여 데이터를 처리하지 않는 컴포넌트로 전달합니다.  그 컴포넌트들은 API 호출하고, 데이터 소스로부터 데이터를 페칭하며, 데이터를 가공하고 나서 state를 세팅합니다. 데이터를 처리하지 않는 컴포넌트는 props를 받아 UI 요소로 되돌려 줍니다.
  3. 여러분이 새로운 컴포넌트를 막 작성하려할 때 state를 어디에 놓아야 하는지가 늘 명확한 것은 아닙니다. 화면에 보일 컴포넌트의 가까운 부모가 되는 container의 일부로 state를 놓을 수도 있습니다.  하지만 더 좋은 방법은, state를 계층구조 상 더 위로 이동시켜 state가 다수의 화면에 보여주는 컴포넌트들에 접근하도록 해주는 것입니다.
  4. 앱의 규모가 커질 때, state가 이곳저곳으로 흩어져 있다는 것을 알게 됩니다. 컴포넌트가 즉각적으로 접근하지 못하는 state에 접근해야 할 때, 가장 근접해 있는 컴포넌트 조상(ancestor)층으로 state를 올려보세요.
  5. 상수(constant) 리팩토링과 소스 코드를 클린업하고 나서는 컴포넌트 계층구조의 상위 위치를 차지하는 대다수의 state로 마무리 될 것입니다. 
  6. 마침내 여러분은 계층 상위에 있는 state를 글로벌하게 처리하고 모든 것을 아래로 전달하는 방식이 좋다라고 결론을 짓습니다. 다른 모든 컴포넌트는 나머지를 필요로하거나 무시할 props를 subscribe하면 됩니다. 

이것이 제가 React를 쓰면서 개인적으로 경험했던 것이고, 다수의 다른 개발자들도 수긍할 것입니다. React는 뷰(view) 라이브러리라서 state를 구체적으로 관리하는 것은 React가 할 일이 아니죠. 우리가 찾는 것은 관심사의 분리(Separation of Concerns) 원칙입니다.

Redux는 React로부터 애플리케이션의 state를 분리하는데 유용합니다. Redux는 애플리케이션의 상위에 자리잡은 글로벌 store를 만들어서 다른 모든 컴포넌트로 state를 공급합니다.  Flux와 달리 Redux에는 store 객체가 많지 않습니다. 애플리케이션의 전체 state는 store 객체 안에 있으며, 어쩌면 store intact를 사용해 뷰 레이어를 다른 라이브러리로 바꿀 수도 있습니다.

컴포넌트는 store가 업데이트될 때마다 다시 렌더링하며 성능에는 미세하게 영향을 미칩니다. 좋은 정보인데요, 이와 함께 수많은 이로운 점들이 따라옵니다.   여러분은 모든 React 컴포넌트를 데이터를 처리하지 않는 컴포넌트로 대할 수 있고, React는 뷰 측면만 집중하면 됩니다.

Redux가 유용한 이유를 알게 되었으니 Redux 아키텍처를 자세히 알아보지요.

Redux 아키텍처

여러분이 Redux를 공부할 때, 잘 알아야 할 한두 가지의 핵심 개념이 있습니다. 아래 보이는 이미지는 Redux 아키텍처와 모든 것이 어떤 방식으로 전부 연결되는지를 설명하고 있습니다.

Getting started with Redux Redux Architecture
Redux 요약 설명

여러분이 Flux를 알고 있다면 요소들 중의 일부가 편하게 보일지 모릅니다. 그렇지 않더라도 괜찮습니다. 기초부터 전체를 다룰 것이기 때문이지요. 우선 redux가 설치되어 있는지 확인하세요. 

create-react-app 혹은 개발서버를 셋업하는 데 여러분이 선호하는 webpack 설정을 이용하세요. Redux는 독립적인 state 관리 라이브러리이므로 아직 React에 연결하지 않겠습니다. 그러므로 index.js의 콘텐츠를 삭제하세요. 이 튜토리얼의 나머지 내용을 Redux로 다루겠습니다.

Store

store은 애플리케이션의 현재 state를 보여주는 수많은 key-value 쌍을 가진 하나의 커다란 자바스크립트 객체입니다.  서로 다른 컴포넌트 전체에 걸쳐 섞여 있는 React에서의 state 객체와 달리, store는 하나만 있습니다. store는 애플리케이션에 state를 제공하고, state가 업데이트될 때마다 view가 다시 렌더링됩니다.

여러분은 절대로 store를 변형시키거나 변화시킬 수 없습니다. 그 대신에 store의 버전을 새로 만드세요.

이러한 이유로 앱이 브라우저에서 실행된 시점으로부터 모든 state를 통해 시간여행을 하게 됩니다. 

store에는 구조상 나머지 부분과 통신하는 세 가지 메서드가 있습니다.  

  • Store.getState()—애플리케이션의 현재 state tree에 접근하는 용도 
  • Store.dispatch(action)—액션을 기반으로 state 변화를 일으키는 용도. 액션에 대한 자세한 내용은 아래 있음.
  • Store.subscribe(listener)—state에서 변화를 감지하는 용도. 액션이 dispatch될 때마다 호출됨.

store를 만들어 봅시다. Redux에 새 store를 만드는 createStore 메서드가 있습니다. 이를 reducer에 넘겨야 하지만, 그게 무엇인지는 알지 못합니다.  일단 저는 reducer라는 이름의 함수를 만들겠습니다. 어쩌면 여러분은 두 번째 인수를 명시해 store의 초기 state를 설정하고 싶을 수 있습니다.

src/index.js

이제 우리는 store에 변화를 감지하고, store의 현재 state 값을 console.log()에 넣어보겠습니다.

그렇다면 store를 어떻게 업데이트 할까요? Redux에는 업데이트를 발생하는 action이라 부르는 무언가가 있습니다. 

Action/Action 크리에이터

Action도 일반적인 자바스크립트 객체로 애플리케이션에서 store로 정보를 전송합니다. 만약에 수를 증가시키는 버튼이 있는 간단한 카운터가 있다고 하면, 그 버튼을 누르는 것으로 action이 발생되는 결과를 낳으며 이는 다음과 같이 보입니다. 

위의 코드는 store로 갈 유일한 정보 소스입니다. store의 state는 action에 관한 반응으로만 변합니다. 각 action에는 action 객체가 무엇을 하려는지 얘기하는 type 속성이 있어야 합니다.  그런 것 말고 action 구조는 여러분이 하기 나름입니다. 그렇더라도 action을 작게 유지하세요. 왜냐하면 action은 애플리케이션 state를 변형하기에 요구되는 최소한의 정보를 나타내기 때문입니다.

가령, 위의 예제에서 type 속성은 “INCREMENT”로 설정되어졌고 추가 payload 속성이 들어갑니다.  payload 속성을 좀 더 의미가 담긴 다른 단어로 이름을 짓거나 여기 경우에는 아예 생략할 수 있습니다. 아래와 같이 action을 store로 dispatch하면 됩니다.

여러분은 Redux로 코드를 작성하면서 보통 action을 직접적으로 사용하지 않을 것입니다. 그보다는 action을 반환하는 함수를 호출합니다. 이런 함수들은 흔히 action 크리에이터라고 알려져 있습니다.  앞서 얘기했던 증가하는 action에 관한 action 크리에이터는 다음과 같습니다. 

자, 카운터의 state를 업데이트하도록 아래 처럼 incrementCount action을 dispatch해야 합니다.

여러분이 브라우저 콘솔로 간다면 부분적으로 동작되고 있는 것을 알게 될 것입니다.  undefined 값을 보게 되는데 이는 reducer를 정의하지 않았기 때문이지요.

Browser console returns undefined for getState

지금까지 action과 store를 다루어 보았습니다. 그렇더라도 action이 제공한 정보를 변환하고 store의 state를 변형하는 메커니즘이 필요합니다.

Reducers

action은 문제를 얘기하고, reducer는 그 문제를 해결하는 담당입니다. 앞의 예제에서 incrementCount 메서드는 state에 행해지기를 원했던 변화 type에 대한 정보를 공급하는 action을 반환했습니다. reducer는 이 정보를 사용해 실제로 state를 업데이트 합니다. 여러분이 Redux를 사용하는 동안 늘 기억해야 할, 문서상에서 강조되는 중요한 사항이 있습니다.

같은 인자가 있다고 한다면, Reducer는 다음 state를 계산하고 그 값을 반환합니다. 당연하겠지요. 부작용도 없습니다. API 호출도 없고요. 변형도 없습니다. 단지 계산만 그럴 뿐입니다. 

reducer가 순수함수라는 의미입니다. input 한 세트가 있다면, 항상 출력값이 같아야 합니다.  그 외에 다른 어떤 것도 하지 않습니다. 더불어 reducer는 AJAX 호출을 한다던지 API에서 데이터를 페칭하는 것과 같이 부작용을 낳는 지점이 아닙니다.

카운터에 관한 reducer를 작성해 보지요.

reducer는 두 개의 인자인 state와 action을 받고, 새 state를 돌려줍니다. 

state는 기본 값인 initialState를 받습니다. 이는 state의 값이 undefined인 경우에만 쓰여집니다.  그 외에는 state의 실제 값을 얻습니다. 정확한 action을 선택하도록 switch 문장을 사용합니다. 브라우저를 새로고침하세요. 그러면 예상했던 대로 기능이 모두 동작하게 됩니다.

카운터가 완벽하지 않은 채로 DECREMENT인 경우를 추가해 봅시다. 

여기에 action 크리에이터가 있습니다.

마지막으로 store로 dispatch합니다.

여기까지 입니다!

요약

이 튜토리얼은 Redux로 state를 관리하는 시작점이 된다는 데에 의의가 있습니다. store와 action, reducer와 같은 Redux의 기초 개념을 이해하는데 반드시 필요한 모든 내용을 다루었습니다.  이 튜토리얼이 끝으로 가면서 동작하는 redux의 데모용 카운터도 제작해 보았습니다. 많지 않더라도 모든 조각들을 하나로 맞추는 방법을 배웠습니다.

지난 한두 해가 지나며 React의 인기가 상승해 왔습니다. 실은 구매하고, 검토하며, 실행 등이 가능한 상품이 marketplace에 풍부하게 있습니다.  React와 관련된 추가 리소스를 찾고 있다면 그 상품들을 망설이지 말고 구매해 보세요.

다음 튜토리얼에서는 Redux를 사용해 React 애플리케이션을 제작하는데 여기서 배운 지식을 활용해 보도록 하겠습니다. 그 때까지 계속 관심을 가져 주세요. 여러분의 의견을 댓글로 남겨 공유해 주시고요. 

Advertisement
Advertisement
Looking for something to help kick start your next project?
Envato Market has a range of items for sale to help get you started.