티스토리 뷰
기존 상태의 비효율성으로 인해 상태 관리 라이브러리가 필요하게 됨
1. 불필요하게 관여된 컴포넌트들도 상태를 가지게 됨
2. 상태 끌어올리기, Props 내려주기를 여러 번 거쳐야 함
3. 애플리케이션이 복잡해질수록 데이터 흐름도 복잡해짐
4. 컴포넌트 구조가 바뀐다면 기존의 데이터 흐름을 완전히 바꿔야 할 수도 있음
* Redux는 React의 하위 라이브러리가 아님
React 없이도 사용할 수 있는 상태 관리 라이브러리
Redux의 구조
Action -> Dispatch -> Reducer -> Store
1. 상태가 변경되어야하는 이벤트 발생 시, 변경될 상태에 대한 정보가 담긴 Action 객체 생성 {type: 'INCREASE'}
2. Action 객체는 Dispatch 함수의 인자로 전달됨
3. Dispatch 함수는 Action 객체를 Reducer 함수로 전달해줌
4. Reducer 함수는 Action 객체의 값에 따라 전역 상태 저장소 Store의 상태 변경
5. 리렌더링
Store
Redux 앱에 state가 저장되어 있는 공간
createStore 메서드를 활용해 Reducer 함수를 연결해서 store 생성
import { createStore } from 'redux';
const store = createStore(rootReducer);
Reducer
Dispatch에게서 전달받은 Action 객체의 type값에 따라 상태를 변경시키는 함수
부수 효과를 방지하기 위해 순수함수여야 함
첫번째 인자에 default value 설정 필수(state 초기값)
두번째 인자: Action 객체
리턴값: 새로운 상태
Reducer의 Immutability(불변성)
Redux의 state 업데이트는 immutable한 방식으로 이루어져야 함(Object.assign(), arr.slice(), spread)
state를 로그로 남겨주는 Redux의 장점과 연관되어있음
const count = 1
// Reducer를 생성할 때에는 초기 상태를 인자로 요구합니다.
const counterReducer = (state = count, action) => {
switch (action.type) {
case 'INCREASE':
return state + 1
case 'DECREASE':
return state - 1
// action === 'SET_NUMBER'일 경우
case 'SET_NUMBER':
return action.payload
// 해당 되는 경우가 없을 땐 기존 상태를 그대로 리턴
default:
return state;
}
}
여러 개의 Reducer를 사용하는 경우 combineReducers 메서드를 사용해 하나로 합쳐줄 수 있음
import { combineReducers } from 'redux'
const rootReducer = combineReducers({
counterReducer,
anyReducer,
...
})
Action
어떤 액션을 취할 것인지 정의해놓은 객체
- type값 필수 지정. 객체가 어떤 동작을 하는지 명시. 대문자와 snake_Case로 작성
- 필요에 따라 payload를 작성
ActionCreater 액션 생성자
보통 Action을 직접 작성하기보다 Action 객체를 생성하는 함수를 만들어 사용
// payload가 필요 없는 경우
{ type: 'INCREASE' }
// Action Creator
const increase = () => {
return {
type: 'INCREASE'
}
}
// payload가 필요한 경우
{ type: 'SET_NUMBER', payload: 5 }
// Action Creator
const setNumber = (num) => {
return {
type: 'SET_NUMBER',
payload: num
}
}
Dispatch
Reducer로 Action을 전달해주는 함수(호출)
전달인자: Action 객체
import { useDispatch } from 'react-redux'
const dispatch = useDispatch()
// Action 객체를 직접 작성하는 경우
dispatch( { type: 'INCREASE' } );
dispatch( { type: 'SET_NUMBER', payload: 5 } );
// 액션 생성자(Action Creator)를 사용하는 경우
dispatch( increase() );
dispatch( setNumber(5) );
Redux Hooks
useDispatch()
(Action 객체를 Reducer로 전달하는) Dispatch 함수를 반환하는 메서드
위 예시 참고
useSelector()
컴포넌트가 Redux의 state에 접근할 수 있게 해주는 메서드
import { useSelector } from 'react-redux'
const counter = useSelector(state => state)
state에는 Store에 저장된 모든 state가 담김
아래처럼 사용할 수도 있음
// 상태 변경
store.dispatch({액션 객체})
// 상태값 얻기
store.getState()
Redux의 세 가지 원칙
1. Single source of truth
동일한 데이터는 항상 같은 곳에서 가지고 와야 함.
= Redux에서 데이터를 저장하는 공간은 Store 단 하나
2. State is read-only
상태는 읽기 전용임.
리액트에서 setState를 사용해 상태를 변경한 것처럼 Redux는 action 객체가 있어야만 상태 변경 가능
3. Changes are made with pure fuctions
변경은 순수 함수로만.
부수효과로 인해 엉뚱한 값으로 상태가 변경되지 않도록 순수함수로 작성해야 함(Reducer)
문자열을 변수로 선언하여 사용하는 이유(문자열 변수화)
1. 오타 방지
2. 자동완성 기능으로 코드 생산성 향상
3. 코드 재사용 용이(Action Creator, Reducer 함수)
Flux 패턴
Dispatcher, Store, View 세 가지로 구성됨
View는 (영향을 받는 모든 View를 업데이트하는, 앱의 데이터와 비즈니스 로직을 갖는) 중앙 디스패처를 통해 Action을 전파
React의 선언형 프로그래밍 스타일과 잘 작동함
ex) 다른 뷰에서 읽지 않은 항목이 강조 표시된 스레드 목록을 표시하면서, 안읽은 메세지 스레드 수를 표시하려 했음
단일 스레드를 읽음으로 표시하면 스레드 모델이 업데이트되고, 읽지 않은 개수 모델도 업데이트해야 하기 때문에
MVC로 처리하기 어려움(MVC: Model, View, Controller)
이러한 종속성 및 계단식 업데이트는 종종 대규모 MVC 앱에서 발생하여
데이터 흐름이 복잡하게 짜여지고, 예측할 수 없는 결과를 초래함(양방향 데이터 바인딩)
데이터 흐름을 디버그하기 어려움

단방향 데이터 흐름은 Flux 패턴의 중심이며 위의 다이어그램은 Flux 프로그래머의 기본 정신 모델이어야 함.
업데이트가 단일 라운드 내에서만 데이터를 변경할 수 있는 경우 시스템 전체가 보다 예측 가능(Predictability)해짐
참고
https://code-cartoons.com/articles/a-cartoon-guide-to-flux/
https://velog.io/@andy0011/Flux-%ED%8C%A8%ED%84%B4%EC%9D%B4%EB%9E%80
https://facebook.github.io/flux/docs/in-depth-overview/
22.12.28
코스 S3U4 Redux 진행중
'코드스테이츠(SEB_FE_42)' 카테고리의 다른 글
| [사용자 친화 웹] 웹 표준 (0) | 2022.12.30 |
|---|---|
| [React] Redux-thunk, Redux Toolkit (0) | 2022.12.29 |
| [React] 상태 관리 (0) | 2022.12.27 |
| [React] storybook(CDD) (2) | 2022.12.23 |
| [JS] XOR 연산 (0) | 2022.12.22 |

