오늘은 Redux에 대해 알아보자

Redux란?
Redux 리덕스란 JavaScript 상태관리 라이브러리이다.
여기서 말하는 상태State란 간단하게 말하자면 데이터를 말한다.
덧붙이자면 상태는 컴포넌트 내부에서 사용하는 데이터라 할 수 있다.
요즘 웹 사이트를 구성할 때, 사용자에게 보이는 UI들을 하나의 파일로 몽땅 구현하지 않고, 요소요소들을 컴포넌트 단위로 구성하여 조합하는 식으로 만드는 추세이다.
Redux의 3가지 원칙
- 진실은 하나의 근원으로부터
- 동일한 데이터는 항상 같은 곳에서 가져온다.
- 즉,
Store스토어라는 하나뿐인 데이터 공간을 만들어 State를 관리한다는 의미이다. - 언제든 어디서든
Store에 저장된 State를 가져다 쓸 수 있다.
- 상태는 읽기 전용이다.
- 리액트에서 setState 메소드를 활용해야만 상태 변경이 가능하다.
- 리덕스에서도 액션이라는 객체를 통해서만 상태를 변경할 수 있다.
- 변화는 순수 함수로 작성되어야 한다.
- 변경하는 순수 함수로만 가능하다.
- 이는 리듀서와 연관되는 개념이다.
- `Store(스토어) - Action(액션) - Reducer(리듀서)
Store, Action, Reducer의 의미와 특징

💡 Store(스토어)
Store는 상태가 관리되는 하나의 공간이다.
- 컴포넌트와는 별개로 스토어라는 공간이 있어서 그 스토어 안에 앱에서 필요한 상태를 담는다.
- 컴포넌트에서 상태 정보가 필요할 때 스토어에 접근한다.
💡 Action(액션)
- Action은 앱에서 스토어에 운반할 데이터를 말한다. (주문서와 같다)
- Action은 자바스크립트 객체 형식으로 되어 있다.
💡 Reducer(리듀서)
Action을Store에 바로 전달하는 것이 아닌,Reducer에 전달해야 한다.Reducer가 주문을 보고Store의 상태를 업데이트하는 것이다.Action을Reducer에 전달하기 위해서는dispatch()메서드를 사용한다.
reducer함수는 기존의 state와 action을 받아서 새로운 state을 받아서 새로운 state를 만들어내는 함수이다.
이벤트 리스너라고 생각하면 된다. 리듀서는 순수함수로서 몇 가지 규칙을 가진다.
root reducer 살펴보기
리듀서는 하나의 리듀서만이 존재한다. 실무에서는 유지 보수를 위해 여러 개의 리듀서를 만든 뒤에 하나의 루트 리듀서로 병합한다. 실제로 어떤 모습을 가지고 있는지 살펴보자
function user(state = "sungjoong", action) {
return state;
}
function post(state = "post1", action) {
return state;
}
리덕스의 combinedReducer api를 활용해 리듀서들을 합친다.
const combined = combineReducer({ user, post });
이렇게 합쳐진 combined 이라는 루트 리듀서는 아래와 같은 모습을 가집니다.
function combined(state = {}, action) {
return {
user: user(state.user, action),
post: post(state.post, action)
};
}
즉, 우리가 dispatch를 통해 루트 리듀서를 호출하면 각각의 리듀서 함수가 실행되고 action이 존재하는 리듀서만이 새로운 상태를 반환 되는데. 눈 여겨볼 점은 combined 함수의 첫번째 인자로 넘긴 state 이고. 현재 초기값이 {}이기 때문에 각각의 리듀서 함수의 첫번째 인자로 넘겨진 state.a와 state.b는 undefined .
만약 초기 상태를 설정하고 싶다면 createStore api에서 2번째 인자인 preloadedState를 넘겨주면 된다.
💡 Dispatch(디스패치)
Dispatch는store의 내장 함수 중 하나로써,action을 발생시킨다.action을 파라미터로 전달하고reducer를 호출한다
💡 Subscribe (구독)
- Subscribe는
sotre의 내장 함수 중 하나로, 특정 함수를 전달해주면action이dispatch되었을 때마다 전달된 함수가 호출된다.
</br >
Action 객체가 dispatch() 메서드에 전달 -> dispatch()를 통해 Reducer를 호출 -> Reducer는 새로운 Store를 생성

Redux의 장점
장점
- 순수 함수를 사용해 상태를 예측 가능하게 만든다.
- 유지보수에 용이하다
redux dv tool이 있어 디버깅에 유리하다.- 비동기를 지원하는
Redux Saga, Redux Thunk등 다양한 미들웨어가 존재한다.
리덕스는 언제🤔 쓰는게 좋을까?
- 전역 상태가 필요하다고 느껴질 때
- 상태들이 자주 업데이트 될 때
- 상태를 업데이트 하는 로직이 복잡할 때
- 앱이 크고 많은 사람들에 의해 코드가 관리될 때
- 상태가 업데이트되는 시점을 관찰할 필요가 있을 때
Redux Thunk 란?
리덕스 창시자인 댄 아브라모프가 만든 가장 많이 사용되는 비동기 작업 미들웨어다. 이 미들웨어를 사용하면 액션 객체가 아닌 함수를 디스패치 할 수 있다.

미들웨어(middleware)란?
리덕스에서 미들웨어는 주로 비동기 처리 할 때 사용한다. 리듀서에서 발생한 예외를 서버로 전송하는 등의 목적으로 미들웨어를 활용할 수 있다.
미들웨어는 리듀서가 액션을 처리하기 전에 실행되는 함수로 액션과 리듀서 사이의 중간자라고 (이미지참고) 볼 수 있다.
리덕스 미들웨어 라이브러리 redux-thunk, redux-saga, redux-observable, redux-promise-middleware 등을 서치해 사용할 수 있고, 만들어서 사용할 수도 있다.
실제 프로젝트를 작업 할 때에는, 미들웨어를 직접 만들어서 사용하는 경우는 그렇게 많지 않다.
redux-thunk는 결국 액션을 자바스크립트 객체뿐 아닌 함수로 보내는 것인데, 액션으로 함수를 보냈을때 이를 실행하는 것이다. 직접 구현하면서 이를 이해해보자
function createThunkMiddleware() {
return ({dispatch, getState}) => next => action => {
if (typeof action === 'function') {
return action(dispatch, getState);
}
next(action);
}
}
위 함수에서 리턴되는 함수가 결국 thunk middleware 함수로, 이 함수는 redux store에서
dispatch, getState api를 받고 , 다음 미들웨어로 액션을 보내는 next를 받는다.
결국 마지막 함수로 우리 dispatch할 액션을 인자로 받는다.
우리가 함수를 dispatch하게 되면 action으로 받고 타입에 따라서 다르게 처리하는 것을 확인 할 수 있다. 따라서 우리가 thunk middleware에 보낼 함수를 작성할때는 아래와 같이 작성한다.
const getUser = (arg) => (dispatch, getState) => {
// 비동기 로직
getState(something);
dispatch(something);
}
dispatch할 때는 아래와 같이 함수를 실행해서 보내주면 되고, 그럼 dispatch와 getState를 인자로 받는 함수 자체를 thunk middleware로 넘기게 된다.
dispatch(getUser(args));
정리
- 리덕스의 동작원리는 액션, 디스패치, 리듀서로 이루어진다.
- 리듀서는 순수함수로서 side effect를 발생시키면 안된다.
- 비동기 로직을 처리하기 위해 리덕스 미들웨어를 사용한다.
- redux-thunk는 함수를 액션으로 보냈을때 처리하기 위함이다.
