리액트는 공통의 조상 컴포넌트에 state 를 위치시키고, useState 를 통해 만든 변경 함수로 state 를 변경합니다. 하지만 이는 컴포넌트가 많아지고 계층이 생길수록 계속해서 props 를 통해 전달해야 하는 불편함을 야기하게 되었죠.
state 관리를 도와주는 리덕스는 어떨까요? 리덕스는 store 를 만들고 여기에서 state 를 관리합니다. 이 store 는 어디에서나 접근 가능한 전역 변수와 같은 개념이기 때문에, props 를 통해 일일히 내려주어야 했던 번거로움이 사라집니다.
공식문서의 store 에 관한 설명 부분을 나름대로 번역해보았습니다.
모든 리덕스 앱의 중심에는 store 가 있습니다. store 란 당신의 앱이 갖는 global state 를 보관하는 보관함입니다.
store 는 자바스크립트 객체이며, 순수한 함수와 비교해 몇가지 특별한 함수와 기능을 가집니다.
- 리덕스 store 안에 있는 state 를 절대 직접적으로 수정하거나 바꾸어서는 안됩니다.
- state 를 업데이트하기 위해서는 "앱에서 발생한 무언가의 변화"를 설명하는 순수한
action
객체를 생성하고,action
을 store 에dispatch
해서 변화를 전달합니다.action
이dispatch
되면, store 는 rootreducer
함수를 실행해 기존의 state 와action
을 기초로 한 새로운 state 를 계산하게 합니다.- 마지막으로 store 는
subscribers
에 state 가 업데이트 되었다는 것을 알려 UI 가 새로운 데이터를 기반으로 업데이트되도록 합니다.
리덕스에서 state 의 변화가 어떻게 진행되고 결과로 이어지는 지를 위의 내용을 통해 이해할 수 있습니다.
리덕스를 시작하려면 먼저 초기 state 를 정의해야 합니다. 리액트에서는 useState 를 활용해 초기 state 와 state 를 변경하는 함수를 함께 만들 수 있었죠. 하지만 우리는 위의 내용을 통해 리덕스에서는 state 를 변경할 때, action
, dispatch
reducer
와 같은 과정이 필요하다는 것을 알게 되었습니다. 따라서 리덕스에서는 우선적으로 초기 state 만 먼저 설정하면 되는 것이죠.
리덕스의 state 는 일반적으로 자바스크립트 객체의 모양으로 이루어집니다. 그 안에 필요한 state 를 키와 값으로 정의하게 되죠. 카운터를 만들어야 한다면 아마 다음과 같은 모양이 될 것입니다.
const initialState = {
value: 0
}
어제의 글에서 reducer
함수를 사용하는 방식으로 Object.assign() 메소드를 언급했었는데요. 리덕스의 state 가 일반적으로 자바스크립트 객체의 모양이기 때문에, 객체를 추가하고 변경하는 메소드인 assign 을 활용할 수 있다는 것을 이해할 수 있습니다.
공식 홈페이지에서 설명하는 reducer 함수의 형태는 다음과 같습니다.
function counterReducer(state = initialState, action) {
switch(action.type) {
case 'counter/incremented':
return { ...state, value: state.value + 1 }
case 'counter/decremented':
return { ...state, value: state.value - 1 }
default:
return state
}
}
reducer
함수는 현재 state 값과 action 객체로 이루어진 2 개의 전달인자를 받게 됩니다. 리덕스 앱이 처음 실행될 때는 아무런 state 도 없기 때문에 앞서 만든 initial state 를 기본 값으로 제공해야 하죠. 그리고 Switch 문을 이용해 action
의 type 에 따라 분기해주고 있습니다.
여기에서 중요하게 살펴보아야 할 점은 ...state 라고 하는 Spread 문법을 활용해 기존 state 의 값을 변경해주고 있다는 점입니다. state 의 value 에 접근해 이를 바로 1로 만들어주는 대신, 기존의 state 를 Spread 문법으로 펼쳐준 이후 다시 state.value + 1 이라는 방법으로 변경하고 있죠.
이것이 앞서서 말한 것처럼 기존의 state 를 직접적으로 수정하거나 교체하지 않고 action
에 의존해 state 를 수정하는 방식입니다. 리덕스 앱에서는 언제나 변화가 action
을 통해 전달되고, action
이 반드시 갖는 type 가 무엇인지를 읽어 type 에 맞는 방법으로 reducer
가 동작하게 됩니다.