함께 성장하는 프로독학러

7. Redux에 대한 이해 본문

Programming/react.js

7. Redux에 대한 이해

프로독학러 2018. 4. 25. 17:17

안녕하세요, 프로독학러 입니다.


이번 포스팅에서는 리덕스를 사용하는 이유와 리덕스의 개념을 정리해 보겠습니다.


* 이번 포스팅의 내용은 velopert 님의 '리덕스 왜 쓸까?' 포스팅을 정리한 내용입니다.

<'리덕스, 왜 쓸까?' - velopert>


리덕스를 이해하기 위해서 먼저 리덕스를 사용하지 않는 환경의 단점을 먼저 파악해 보겠습니다.


간단한 예를 통해 살펴보겠습니다.


만약 다음 그림과 같이 세 개의 컴포넌트가 있다고 합시다.

A 컴포넌트는 B 와 C 컴포넌트의 부모 컴포넌트입니다.


B 컴포넌트는 A 의 상태를 변경하는 함수를 실행하는 컴포넌트입니다. 

(A의 상태를 변경하는 메소드 _increase 를 increNum 프롭스로 전달받습니다.)


C 컴포넌트는 A 컴포넌트의 상태(state)를 렌더링하는 컴포넌트입니다.

(A의 상태를 numValue 프롭스로 전달받습니다.)


위의 어플리케이션이 동작하는 방식은, B 컴포넌트를 통해 A 컴포넌트의 상태를 변경하고, A 의 변경된 상태를 C 가 렌더링 하는 방식입니다.

동작과 반응을 하는 컴포넌트는 B 와 C 이지만, 모두 A 컴포넌트를 거쳐서 실행됩니다.


위처럼 간단한 어플리케이션에서는 리덕스를 사용하지 않아도 큰 문제는 없습니다.

하지만 만약 어플리케이션의 규모가 커지고, 컴포넌트의 수가 많아지면 어떨까요?



만약 위의 그림처럼 어플리케이션이 복잡해져 컴포넌트가 많은 상황이라면 어떨까요?

I 컴포넌트가 A 의 상태를 변경하는 버튼이 포함된 컴포넌트이고, F 컴포넌트는 A 의 상태를 렌더링하는 컴포넌트라고 가정해 봅시다.


A 컴포넌트에서 정의한 자신의 상태를 바꾸는 메소드 _increase 를 A 컴포넌트가 렌더링 될 때 B 컴포넌트로 increNum 프롭스로 전달해 줍니다.

그리고 B 는 자신이 increNum 프롭스로 전달받은 메소드를 다시 E 에게 increNum 프롭스로 넘기고, E 는 H 로, H 는 I 로 넘깁니다.

그리고 최종적으로 I 컴포넌트안의 버튼 태그에서 onClick 이벤트로 전달받은 메소드를 지정합니다.


A 의 상태를 렌더링하는 F 컴포넌트는 A의 상태를 C 를통해 전달받아 렌더링 합니다.


위와 같은 어플리케이션에서 I 컴포넌트가 A 의 상태를 변경하고 바뀐 A 의 상태를 F 가 렌더링하려면 A, I, F 컴포넌트 이외에 쓸데없이 B, E, H, C 가 관여하게 됩니다.

이러한 구조에서 만약 props 의 이름을 바꾸거나 헷갈리게 되는 상황이라도 벌어지게 된다면 끔찍한 상황이 벌어질 수 있겠죠?


이와 같은 비효율적인 구조를 벗어나기 위해서 사용하는것이 '리덕스' 입니다.


리덕스는 상태를 컴포넌트에 종속시키지 않고 컴포넌트의 바깥쪽에서 상태를 관리합니다.


아까와 같은 구조를 가진 어플리케이션에 리덕스를 사용하면 다음 그림과 같은 구조가 됩니다.



이제 어플리케이션의 상태는 컴포넌트 안에서 관리되는 것이 아닌 리덕스 스토어에서 관리됩니다. (스토어 안에 상태가 존재합니다.)

리덕스가 작동되는 방식에 대해서 순서대로 알아봅시다.


1) 컴포넌트의 리덕스 스토어 구독


위의 어플리케이션의 F 컴포넌트는 변경된 상태를 렌더링 하는 역할을 수행합니다.

따라서 F 컴포넌트는 아래의 그림과 같이 리덕스 스토어를 구독합니다.


구독은 store의 메소드 중 하나인 subscribe 를 통해서 하는데, 메소드의 인자는 콜백함수입니다.

스토어의 상태가 변경되면 스토어는 자신을 구독하고 있는 컴포넌트로 listener 콜백함수를 실행하여 상태 변경을 전달합니다.


2) 스토어에 상태 변경을 요청


컴포넌트 I 는 상태를 변경하는 함수를 실행하는 버튼에 이벤트를 통해서 실행하는 컴포넌트입니다.

리덕스를 사용하는 환경에서는 I 의 버튼이 클릭되면 store 의 메소드 중 하나인 dispatch 를 호출합니다.

dispatch 는 스토어에게 상태를 변경해달라고 요청하는 메소드 입니다.

dispatch 메소드의 인자로 action 객체가 들어오는데, action 객체는 스토어가 상태를 변경할 때 참고할 내용입니다.

모든 action 객체에는 type 속성이 있는데, 스토어는 이 action 객체의 type 에 따라 어떻게 상태를 변경할지 결정합니다.


3) 스토어 안의 리듀서가 스토어의 상태를 변경


I 컴포넌트로 부터 dispatch 를 통해 action 객체를 전달받으면 스토어의 내부에 있는 리듀서라는 함수가 상태를 변경합니다.

리듀서 함수는 두개의 인자를 받는데, 첫 번째 인자는 state (스토어의 이전상태) 이고, 두 번째 인자는 action 객체입니다.

리듀서 함수는 이전상태와 액션객체를 이용하여 새로운 상태를 리턴합니다.

그리고 스토어는 리듀서로 부터 만들어진 새로운 상태를 자신의 상태로 갈아끼웁니다.

(이전의 상태를 변경하는 것이 아닌 새로운 상태로 대체)



1. 스토어 안의 리듀서가 dispacth 로 받은 액션과 스토어의 prevState 를 받는다

2. 리듀서 함수가 작동하여 새로운 상태(newState) 를 반환한다.

3. 새로 생성된 상태를 스토어의 상태로 갈아끼운다.


4) 상태변화가 일어나면 구독하고 있던 컴포넌트에게 알림


리듀서를 통해 상태가 변경되면 스토어를 구독하고 있던 컴포넌트에게 상태가 변경됐음을 알려줍니다.



알려주는 것은 구독할 때 등록했던 콜백함수를 실행하는 것을 통해 합니다.

콜백함수를 전달받은 lisnter 는 리렌더링을 실행합니다.


즉, 리덕스를 활용하면 상태 변경을 부모로부터 자식, 그 자식의 자식 으로 넘겨주는 것이 아니라 어떤 컴포넌트던간에 바로 상위의 컴포넌트로 부터 props 를 전달받는 것 처럼 동작하게 할 수 있습니다.


리덕스를 활용해 상태관리를 외부에서 하는 순서는 다음과 같습니다.


1. 액션 타입 생성 (action 은 객체이며, type 속성을 반드시 가지고 있어야 한다.)

2. 액션 생성 함수 정의 (액션 생성 함수를 통하여 action 객체를 빠르게 만들 수 있도록 도와줌)

3. 실질적으로 변화를 일으키는 함수인 리듀서 정의 (인자로는 prevState와 action이 들어옴, 들어오는 action 객체의 타입에 따라 어떤 변화를 일으킬지 정의)

4. 스토어 생성 (3에서 만든 리듀서를 포함하여 createStore를 통해 생성)

5. 스토어의 변화가 생길때 실행될 리스너 함수 정의

6. 클릭 등 이벤트에 dispatch 를 통해 액션 전달


지금까지 리덕스를 리덕스를 사용하지 않은 환경과 비교하여 이해하여 봤습니다.

다음 포스팅에서는 리덕스를 실제로 사용하여 간단한 어플리케이션을 만들어 보도록 하겠습니다.

(위의 순서를 잘 기억해 주세요)

감사합니다.


**참고 자료 (항상 감사드립니다)

https://velopert.com/3528


*다녀가셨다는 표시는 공감으로 부탁드릴게요! (로그인 하지 않으셔도 공감은 가능합니다 ㅎㅎ)



Comments