안녕하세요
Redux는 자바스크립트를 위한 상태관리 프레임워크입니다.
리액트에서 상태값을 하위 컴포넌트에 전달할 때, 그 깊이가 깊어질 수록 복잡도가 올라갑니다. ContextAPI를 사용할 수도 있지만 이 경우도 여러개를 중첩해서 사용하게되면, 전달하는 컴포넌트나 사용하는 컴포넌트에서도 마찬가지로 복잡도가 올라갑니다.
반대로 하위 컴포넌트에서 상위 컴포넌트로 값을 전달해야 하는경우에는 이벤트를 하위 컴포넌트에 전달해 사용하는데, 이 경우에도 마찬가지로 복잡도가 올라갑니다.
그리고 이런 동일한 기능을 위한 반복되는 작업은 지칩니다.
Redux는 이러한 상태값 관리를 직렬화 해서 하나의 객체에서 관리합니다.
모든 컴포넌트는 이 하나의 객체에서 상태값을 참조하게 되어 이해하기쉬울 뿐 아니라 상태값 제어에 관한 모든 것을 하나의 객체를 통해 할 수 있기 때문에 관심사 분리가 용이하며 테스트 환경도 좋아집니다.
MVC패턴을 사용하던 Facebook에서는 고질적인 문제를 해결하기 위해 Flux아키텍쳐를 만들었습니다. 규모가 큰 서비스에서는 MVC패턴이 보다 Flux구조가 좋다고 말합니다.
그리고, Redux는 flux아키텍쳐를 구현체들 중 하나로 React와 잘 어울립니다.
Action은 사용자와 애플리케이션간의 상호작용이나 타이머, 웹소켓등 에서 발생하는 이벤트라고 할 수 있습니다.
Action은 고유한 이름(type)과 포함하는 데이터(payload)를 가지고 있습니다.
const add = {
type: "USER_ADD", // type
payload: { // payload
name: "junhyuk",
age: "70"
}
}
Dispatcher는 Action을 Store에 전달하는 역할입니다.
store의 상태(앱 전체의 상태)는 Dispatcher에 의해서만 변경되며, 이 것이 단방향 흐름을 보장해줍니다.
store는 애플리케이션의 거의 모든 상태를 가지고 있습니다. 개발자가 일부러 컴포넌트 내에서만 사용할 목적으로 store에서 관리하지 않도록 한 경우는 제외입니다.
store의 데이터는 Dispatcher를 통해서만 변경될 수 있습니다.
사용자가 보는 화면입니다. 이 화면에서 앱과 사용자의 상호작용, 이를테면 버튼 클릭등 이벤트(Action)가 발생하면 Dispatcher에 등록된 콜백함수를 통해 Store에 전달되어 상태값이 변경됩니다.
그리고 상태값 변경에 따른 View도 함께 변경됩니다.
이런 재귀적인 흐름이 Flux의 기본구조입니다.
React는 이 구조에서 View를 담당합니다.
그리고 Redux가 나머지 Action, Dispatcher, Store를 담당합니다.
Redux와 React가 잘 조합되지만 Redux가 React만을 위해 만들어진 것은 아닙니다.
Redux는 JavaScript앱을 지원합니다.
npm i redux
공통점은 Action, Dispatch, Store, View가 존재한다는 것, 단방향 데이터 플로우를 가지는 것, View와 결합되지 않았다는 것입니다.
가장 큰 차이점은 Redux가 Reducer를 필수로 가져야 한다는 것입니다.
Redux를 시작할 때 가장 먼저 하는 것은 reducer를 작성하고, 이 reducer로 Store를 생성하는 것입니다.
import { createStore } from 'redux'
Reducer함수는 state와 action을 매개변수로 가집니다.
매개변수에 초기값을 설정할 수도 있고 따로 변수로 작성해도 됩니다.
const INITIAL_STATE = {
...
}
function counter(state=INITIAL_STATE, action) {
switch (action.type) {
case 'INCREMENT':
return state + 1
case 'DECREMENT':
return state - 1
default:
return state
}
}
그런다음
Store를 생성해주는 redux의 함수 createStore의 인자로 방금 작성한 reducer를 넣어 초기화합니다.
let store = createStore(counter)
store의 상탯값이 변경되었다면 View역할을 맡고있는 React에게 알려줘야합니다. store가 갖고있는 메서드 들중 subscribe를 이용합니다.
subscribe메서드는 action이 dispatch되고, store가 변경될 때마다 실행할 콜백함수를 정의할 수 있는데 React에서는 state가 변경되면 자동으로 업데이트되므로 setState를 콜백으로 넣어 View에서 변경됐음을 사용자에게 알릴 수 있습니다.
store.subscribe(()=>setState(updated))
여기서 store.getState()를 이용해 로그를 출력할 수도 있고, setState를 할 수도 있습니다.
store.subscribe() 함수는 구독을 해제하는 함수를 리턴합니다.
따라서 별도의 패키지 (react-redux)를 사용하지 않는 경우 이런 패턴으로 사용됩니다.
componentDidMount() {
this.unSubscribe = store.subscribe(() => console.log(store.getState()))
}
componentDidUnMount() {
this.unSubscribe()
}
store의 상태값을 변경하는 유일한 방법은 dispatch(action)입니다.
action은 type속성으로 고유한 상수를 가진 객체입니다.
store.dispatch({ type: 'INCREMENT' })
store.dispatch({ type: 'DECREMENT' })
여기서 Action은 { type: 'INCREMENT' }
와 { type: 'DECREMENT' }
입니다.
store.dispatch(action)
dispatch 함수로 action을 store에 넘겨주는 형태입니다.
import { createStore } from 'redux'; // redux의 createReducer
function counter(state = 0, action) { // reducer작성
switch (action.type) {
case 'INCREMENT':
return state + 1
case 'DECREMENT':
return state - 1
default:
return state
}
};
let store = createStore(counter); // reducer로 store초기화
store.subscribe(() => console.log(store.getState())); // 구독
// dispatcher에 action을 이용해 store상탯값 변경
// action.type에 따라 store가 다른 기능을 수행할 수있음
store.dispatch({ type: 'INCREMENT' });
store.dispatch({ type: 'INCREMENT' });
store.dispatch({ type: 'DECREMENT' });
state의 초기값은 0입니다.
store.dispatch()가 실행될 때마다 store의 콜백함수가 실행됩니다.
store.getState()는 store의 상탯값을 리턴하는 함수입니다.
따라서 결과는 아래와 같습니다.
1
2
1
다음 포스팅에서 React와 Redux를 함께 사용하는 법을 알아보겠습니다.