Redux
- 상태 관리 라이브러리
- 리액트에 종속되는 라이브러리가 아니다.
- 리액트에서 사용하려고 만들어졌지만 다른 UI 라이브러리/프레임워크와 함께 사용할 수 있다. (angular-redux 등 ...)
- 상태 업데이트 관련 로직을 다른 파일로 분리시켜서 효율적으로 관리할 수 있다
- 리액트에서는 v16.3의 Context API를 기반으로 동작한다.
액션 action
- 상태에 변화가 필요하면 액션이 발생한다.
- 하나의 객체로 표현되고
type
필드를 반드시 가지고 있어야 한다. - 프로젝트의 상태에 변화를 일으키는 것을
액션
이라고 한다. - 액션 이름은 문자열 형태이고 주로 대문자로 작성하며 고유해야 한다. (중복되면 에러가 발생될 수 있다)
- 주로
module_name/action_type
형태 (excounter/INCREASE
)
- 주로
액션 생성 함수 action creator
- 액션 객체를 만들어 주는 함수
type
필드를 포함한 객체를 리턴해준다. 다른 필드도 자유롭게 추가할 수 있다
리듀서 reducer
- 변화를 일으키는 함수
- 액션이 발생하면 리듀서가 현재 상태와 전달받은 액션 객체를 파라미터로 받아 온다.
- 두 값을 참고하여 새로운 상태를 만들어서 반환한다.
- 상태의 불변성을 유지하면서 데이터를 변화시켜야 한다.
초깃값
- 형태는 자유 (객체, 배열, 문자열 ...)
- 리듀서 생성시 초깃값을 전달해야 한다.
스토어 store
- 한 개의 프로젝트는 단 하나의 스토어만 가질 수 있다.
- 현재 어플리케이션의 상태와 리듀서, 내장 함수(dispatch, subscribe)를 가진다.
- 스토어 생성시 하나의 리듀서만 등록할 수 있다.
디스패치 dispatch (스토어 내장함수)
- 액션을 발생시키는 것
dispatch(action)
과 같은 형태로 액션 객체를 파라미터로 넣어서 호출- 이 함수가 호출되면 스토어는 리듀서 함수를 실행시켜서 액션 객체에 따라 새로운 상태를 만들어 준다.
구독 subscribe (스토어 내장함수)
subscribe
함수 안에 리스너 함수를 파라미터로 넣어서 호출하면
리스너 함수가 액션이 디스패치 되어 상태가 업데이트될 때마다 호출된다- 리액트에서 스토어의 상태값이 변할 때 마다 해당 상태값을 사용한 컴포넌트가
re-render
되어야 하는데 이 작업을react-redux
에서 처리해준다
Ducks 패턴
- 액션 타입, 액션 생성 함수, 리듀서 함수를 기능별로 파일 하나에 작성하는 방식
- 리덕스 공식 문서에서도 사용하는 가장 일반적인 구조는
actions
,constants
,reducers
라는 세 개의 디렉터리를 만들고 그 안에 기능별로 파일을 하나씩 만드는 구조 - Ducks 패턴을 사용해서 액션 타입, 액션 생성 함수, 리듀서를 작성한 파일(코드)을 "모듈"이라고 한다.
리덕스 미들웨어 (Redux Middleware)
- 액션을 디스패치했을 때 리듀서에서 이를 처리하기 전에 사전에 지정된 작업들을 실행한다.
- 액션과 리듀서 사이의 중간자 역할을 한다.
- 액션을 기록하거나 취소하거나 다른 종류의 액션을 추가로 디스패치할 수도 있다.
- 함수를 반환하는 함수를 반환하는 함수 (
middleware = store => next => action => {}
) - 스토어를 생성할 때 전달한다
store
- 리덕스 스토어 인스턴스
- 상태 가져오기: store.getState()
next
- 함수 형태
- store.dispatch와 비슷한 역할을 한다
- next(action)을 호출하면 그다음 처리해야 할 미들웨어에게 액션을 넘겨 준다.
- 그다음 미들웨어가 없다면 리듀서에게 액션을 넘겨 준다.
- next를 사용하지 않으면 액션이 리듀서에 전달되지 않는다. (액션이 무시되는 것)
- next를 기준으로 store의 state가 변경된다.
action
- 디스패치된 액션
리덕스의 세 가지 규칙
단일 스토어
- 하나의 애플리케이션에는 하나의 스토어가 있다
- 여러 개의 스토어를 사용할 수 있지만 상태 관리가 복잡해질 수 있으므로 권장하지 않는다.
읽기 전용 상태
- 상태를 업데이트할 때 기존의 객체는 건드리지 않고 새로운 객체를 생성해 주어야 한다. (불변성 유지)
- 불변성을 유지해야 하는 이유는 내부적으로 데이터가 변경되는 것을 감지하기 위해 얕은 비교(shallow equality) 검사를 하기 때문이다.
- 겉핥기 식으로 비교하여 좋은 성능을 유지할 수 있다.
리듀서는 순수한 함수
- 리듀서는 이전 상태와 액션 객체를 파라미터로 받는다.
- 파라미터 외의 값에는 의존하면 안 된다.
- 이전 상태는 절대 건드리지 않고, 변화를 준 새로운 상태 객체를 만들어서 반환한다. (불변성)
- 똑같은 파라미터로 호출된 리듀서 함수는 언제나 똑같은 결과 값을 반환해야 한다.
- 리듀서 함수 내부에서 랜덤 값을 만들거나 Date 함수를 사용하거나 네트워크 요청을 하면 안된다
- 같은 입력에 다른 결과가 나올 수 있기 때문에
- 이러한 작업은 리듀서 함수 바깥에서 처리해야 한다.
- 액션을 만드는 과정에서나 리덕스 미들웨어에서 처리한다
- 네트워크 요청과 같은 비동기 작업은 리덕스 미들웨어를 통해 관리한다.
리덕스의 작성 흐름
- rootReducer 생성:
combineReducers
사용해서 다수의 리듀서들을 합친다. - 스토어 생성 (rootReducer 사용) (
createStore
-redux)- 미들웨어가 있다면 추가 (
applyMiddleware
-redux)
- 미들웨어가 있다면 추가 (
- 어플리케이션에 적용 (store를 Provider에 전달) (
Provider
-react-redux) - 모듈 생성
- 액션 타입 정의
- 액션 생성 함수 작성 (사용 가능:
createAction
-redux-actions) - 리듀서의 초깃값 설정
- 액션 타입에 따른 리듀서 작성 (초깃값 사용) (사용 가능:
handleActions
-redux-actions)
- 프레젠터 컴포넌트 작성
- 컨테이터 컴포넌트 작성
- 모듈에서 액션 생성 함수 가져오기
- 스토어에서 상태값 가져오기 (사용 가능:
connect
,useSelector
-react-redux) - 스토어에서
dispatch
를 가져오기 (사용 가능:useDispatch
-react-redux) - 디스패치의 인자로 액션 생성 함수를 이용해서 액션 객체를 생성해서 전달
- 디스패치 함수를 실행하는 함수를 생성
- 스토어의 상태값과 디스패치 함수를 실행하는 함수를 프레젠터 컴포넌트의 props로 전달
리덕스 관련 라이브러리
react-redux
- 스토어 상태가 바뀔 때마다 render 함수가 호출되도록 작업해준다.
- 리덕스 상태를 조회하는 작업을 대신해준다
- Hooks 제공 => 리덕스 스토어와 컨테이너 컴포넌트를 만들 때 사용 가능하다
- useSelector:
react-redux
의connect
함수를 사용하지 않고도 리덕스의 상태를 조회할 수 있다. - useDispatch: 컴포넌트 내부에서 스토어의
dispatch
를 사용할 수 있게 해준다. - useStore
- useSelector:
redux-actions
- 액션 생성 함수를 더 짧은 코드로 작성할 수 있다:
createAction
- 리듀서 함수를 간단하고 가독성 높게 작성할 수 있다:
handleActions
redux-logger
- 액션 정보와 상태를 보여주는 로깅 미들웨어
redux-thunk
- 비동기 작업을 처리할 때 가장 많이 사용하는 미들웨어
- 리덕스의 창시자인 댄 아브라모프가 만들었음
- 객체가 아닌 함수 형태의 액션을 디스패치할 수 있게 해준다.
- thunk 함수를 만들어서 디스패치할 수 있다.
- 리덕스 미들웨어가 그 함수를 전달받아 store의 dispatch와 getState를 파라미터로 넣어서 호출해준다.
redux-saga
redux-thunk 다음으로 많이 사용되는 비동기 작업 관련 미들웨어
특정 액션이 디스패치되었을 때 정해진 로직에 따라 다른 액션을 디스패치 시키는 규칙을 작성하여 비동기 작업을 처리할 수 있게 해준다.
우리가 디스패치하는 액션을 모니터링해서 그에 따라 필요한 작업을 따로 수행할 수 있는 미들웨어
redux-thunk 보다 조금 더 까다로운 상황에서 유용하다
- 기존 요청을 취소 처리해야 할 때 (불필요한 중복 요청 방지)
- 특정 액션이 발생했을 때 다른 액션을 발생시키거나, API 요청 등 리덕스와 관계없는 코드를 실행할 때
- 웹소켓을 사용할 때
- API 요청 실패 시 재요청해야 할 때
ES6의 제너레이터(generator) 함수라는 문법을 사용함
제너레이터 함수를 사가(saga)라고 부른다.
takeEvery: 들어오는 모든 액션에 대해 특정 작업을 처리한다.
takeLatest: 기존에 진행 중이던 작업이 있다면 취소 처리하고 가장 마지막으로 실행된 작업만 수행한다.
- 여러 액션이 중첩되어 디스패치되었을 때는 기존의 것들은 무시하고 가장 마지막 액션만 제대로 처리한다.
루트 사가가 필요하다. 여러 리듀서에서 만든 사가를 등록해야 하기 때문에
- all: 여러 사가를 합쳐 주는 역할
- 스토어에 루트 사가 미들웨어를 적용한다
출처
'React' 카테고리의 다른 글
[React] import path에 상대 경로를 절대 경로로 변경하기 (0) | 2020.12.27 |
---|---|
[React] Error: Node Sass version 5.0.0 is incompatible with ^4.0.0 (0) | 2020.12.22 |
[ React ] React.PureComponent (0) | 2018.01.06 |
댓글