[Redux] Redux 기본개념
🧐 서론
드디어, React 세계에서 한 걸음(어떻게 보면 큰 보폭)을 내딛는 리덕스를 공부하기 시작했다!
중앙 상태관리를 통해 props Drilling의 복잡성을 줄이기 위한 라이브러리 라는 정도로만 알고 있었다.
물론 현재는, Context API 나 함수형의 useContext, useReducer Hooks 들로 일부 대체가 가능하고, graphQL, Apollo 와 같은 차선책들이 등장하고 있다고 알고 있다.
하지만, 상태관리의 '근본'이자 그만큼 아직까지도 많은 기업에서 사용중인 Redux를 공부해보고 다음 프로젝트에 적용시키면서,
상태관리 학습을 위한 기반을 다지고자 한다!!
💜 Redux(리덕스) 란?
Redux is a predictable state container for JavaScript apps.
Redux는 자바스크립트 앱을 위한 예측 가능한 상태 컨테이너라고 공식문서는 정의하고 있다.
즉, Redux는 React 만을 위한 라이브러리는 아닌 것이다. Angular를 위한 ng-redux도 있고, 심지어 vanila JS에서도 적용 가능하다.
특히, React + Redux 조합이 애용되는 이유는, Redux가 React의 작동원리 중 하나인 상태변화를 쉽게 예측하도록 돕기 때문이다.
또한, 상태관련 로직을 하나의 파일이 통합관리하기 때문에, 구성이 간결해지고 효율성이 높아진다. (props drilling 감소)
추가로, 리덕스는 생태계가 거대해서 다양한 미들웨어를 통해 비동기 작업, 로깅, 디버깅 등을 지원받을 수 있는 장점이 있다.
💜 Redux(리덕스) 의 필요성
사실, 단순한 앱의 경우 상태관리의 필요성은 적다. App.js 혹은 하나의 상위 컴포넌트에서 중앙처리가 가능하기 떄문이다.
하지만, 프로그램 규모가 커질수록 이는 다양한 난관에 봉착하게 될 것이다.
- 다뤄야 할 state가 무척 많아진다. 이는, 컴포넌트에서 사용되는 'local state'와 전체적으로 통용되는 'global state'로 나뉜다.
- global state는 여러 컴포넌트에 영향을 미친다. 즉, 관련된 컴포넌트들에 props를 각각 전달해줘야되는 것이다.
- 다단계의 상/하위 컴포넌트로 이루어졌다면, props depth가 깊어지고 불필요한 중간 컴포넌트를 거치는 비효율성이 생긴다.
이러한 문제점들을 해결하기 위해 상태관리 개념과 Redux가 등장하게 된 것이다.
앱의 상태와 상태변화 로직을 Redux Store에서 관리하고, 이를 필요한 컴포넌트에만 선택적으로 연계할 수 있는 것이다.
Global State 관리는 매우 유리해지고 props drilling 역시 간소화해진다. 그렇다면 Redux가 무조건 유리한 것일까?
- Redux(리덕스) 를 사용해야 하는가?
공식문서도, 무조건적인 Redux 사용을 권장하지는 않는다. 모든 상태가 중앙에서 관리된다면, 그것 또한 스토어 부하가 될 것이다.
Redux를 사용하기 적절한지 판단하기 위해 공식문서는 다음 조건들을 제시한다.
- 계속해서 바뀌는 상당한 양의 데이터가 있다. (리스트 페이지 목록데이터)
- 상태를 위한 단 하나의 근원이 필요하다. (모달창 로그인/회원가입 모드)
- 최상위 컴포넌트가 모든 상태를 갖고 있는 것이 적절하지 않다. (메인 페이지의 네브바, 검색값, 추천리스트 등등)
💜 Redux(리덕스) 기본개념
- Redux(리덕스) 3원칙
1. Single source of truth
우리의 앱 전체상태는 단일스토어로 관리합니다.
단일스토어는 앱 전체를 쉽게 관리할 수 있는 범용성을 가지고, 또한 디버깅이나 개발자도구를 쉽게 사용할 수 있게 합니다.
2. State is read-only
상태는 ‘읽기 전용’ 이며, 상태를 변경할 수 있는 유일한 방법은 ‘액션 객체’를 이용하여 ‘액션’을 발생시키는 것입니다.
3. Changes are made with pure functions
리덕스의 리듀서는 순수 함수이어야 합니다. 여기서 순수함수란 어떤 함수에 동일한 파라미터를 주었을때 항상 같은 값을 리턴하고, 외부의 상태를 변경하지 않는 함수입니다. 리듀서는 이전의 상태와 액션을 받아서 다음 상태를 반환하는 순수한 함수입니다. 한개의 리듀서부터 시작해서 여러개의 리듀서들까지 한개의 상태트리에서 관리하게 됩니다.
- Redux(리덕스) 주요 키워드
1. 액션(Action)
상태에 변화가 필요할 때, 액션을 발생시킨다. 액션은 하나의 객체로 표현된다.
// basic action
{
type: 'increment',
}
// action with data
{
type: 'add_data',
text: 'new data!',
}
{
type: 'add_data',
data: {
id: 1,
content: 'new data!',
}
}
액션 객체는 type 필드를 필수로 가지고 있어야 한다. 이외의 값은 임의로 넣을 수 있다.
* 액션 생성함수(Action Creator)
액션 생성함수는, 파라미터를 받아와서 액션 객체를 반환하는 형태의 함수이다.
function addTodo(data) {
return {
type: "ADD_TODO",
data
};
}
const changeInput = text => ({
type: "CHANGE_INPUT",
text
});
2. 리듀서(Reducer)
액션이 발생했을 때, 정의된 행동(type)에 따라 상태를 변화시키는 함수이다. 수정 후 변환된 state를 반환한다.
function reducer(state = initialState, action) {
switch (action.type) {
case SET_VISIBILITY_FILTER:
return Object.assign({}, state, {
visibilityFilter: action.filter
});
default:
return state
}
}
* Object.assign() : 객체의 열거와 병합
// 객체 병합
const target = { a: 1, b: 2 };
const source = { b: 4, c: 5 };
const returnedTarget = Object.assign(target, source);
console.log(returnedTarget); // { a: 1, b: 4, c: 5 }
// 객체 다중병합
const o1 = { a: 1, b: 1, c: 1 };
const o2 = { b: 2, c: 2 };
const o3 = { c: 3 };
const obj = Object.assign({}, o1, o2, o3);
console.log(obj); // { a: 1, b: 2, c: 3 }
assign() 메서드는 첫 번째 인자로 target 객체, 두 번째 인자부터는 source 객체들을 받는다.
객체들을 하나로 열거해주며, 중복되는 필드의 값은 하나로 병합해준다. 최신화는 후순위 source 값들이 반영된다.
3. 스토어(store)
스토어는 현재의 앱 상태(state), 리듀서(reducer), 기타 내장함수가 포함되어 있다. 한 어플리케이션 당 하나의 스토어만 만든다.
import { createStore } from 'redux';
import reducer from './reducers';
let store = createStore(reducer);
4. 디스패치(dispatch)
디스패치는 스토어(store)의 내장함수 중 하나이다. 디스패치의 역할은 액션의 발생이라고 이해하면 된다.
dispatch(action) 이런 식으로, 액션을 인자로 받는다. 그러면, 스토어는 리듀서 함수를 실행시켜 액션 타입에 따른 상태를 수정한다.
5. 구독(subscribe)
구독 역시 스토어(store)의 내장함수 중 하나이다. 구독의 역할은 주기적인 함수의 실행이다.
subscribe(function) 이런 식으로, 함수를 인자로 받는다. 액션이 디스패치될 때마다 해당 함수가 실행된다.
확실히, useContext / useReducer 를 한 번 써본 뒤 Redux를 접하다 보니 러닝커브가 많이 완화된 기분이다.
액션 / 디스패치 / 리듀서 플로우를 직접 토이 프로젝트를 만들면서 이해한다면, Redux의 강점인 원활한 상태관리가 가능하리라!
다른 핫한 상태관리 툴로 MobX가 있다. 이는 상대적으로 더 사용하기 편리하다고 한다. (나중에 공부해보아야 겠다!!)
[출처]
- Redux 공식문서: ko.redux.js.org/introduction/getting-started/
- 벨로퍼트 님의 블로그: velog.io/@velopert/Redux-1-%EC%86%8C%EA%B0%9C-%EB%B0%8F-%EA%B0%9C%EB%85%90%EC%A0%95%EB%A6%AC-zxjlta8ywt
- 조승현 님의 블로그: medium.com/@jsh901220/react%EC%97%90-redux-%EC%A0%81%EC%9A%A9%ED%95%98%EA%B8%B0-a8e6efd745c9