반응형
리덕스는 자바스크립트를 위한 상태 관리 프레임워크
- 컴포넌트와 상태 관리 코드 분리
- 서버 렌더링 시 데이터 전달이 간편하다
- 알림창과 같이 전역 컴포넌트의 상탯값을 관리할 때 좋다
- 페이지가 전환되어도 데이터는 살아 있어야 할 때 좋다
6.1 리덕스 사용 시 따라야 할 세 가지 원칙
- 하나의 객체에 프로그램의 전체 상탯값을 저장한다
- 상탯값을 불변 객체로 관리한다
- 상탯값은 오직 액션 객체에 의해서만 변경되어야 한다.
- 오직 순수 함수에 의해서만 상탯값을 변경해야 한다
// [홍길동]님 안녕하세요, [지금은 11시 30분]입니다.
sayHello('홍길동')
sayHello('홍길동', '11:30')
6.2 리덕스의 주요 개념 이해하기
- 리덕스에서 상탯값이 변경되는 과정

6.2.1 액션
- 액션은 type 속성값을 가진 자바스크립트 객체다.
- 액션 객체를 dispatch메서드에 넣어서 호출하면 리덕스는 상탯값을 변경하기 위해 위의 과정을 수행한다
const ADD = 'todo/ADD'
store.dispatch({type:ADD, title:'영화보기'});
store.dispatch({type:'todo/REMOVE', id:123});
- type 속성값은 상수 변수로 만드는게 좋다.
6.2.2 미들웨어
- 리듀서가 액션을 처리하기 전에 실행되는 함수
const printLog = store => next => action => {
console.log(`prev state = ${store.getState()}`)
const result = next(action)
console.log(`next state = #{store.getState()}`)
return result
}
6.2.3 리듀서
- 액션이 발생했을 때 새로운 상탯값을 만드는 함수
function reducer(state = INITIAL_STATE, action) {
switch (action.type) {
case REMOVE_ALL:
return {
...state,
todos: [],
}
case: REMOVE:
return {
...state,
todos: state.todos.filter(todo => todo.id !== action.id),
}
- 상탯값은 항상 불변 객체로 관리해야 한다.
immer를 이용하여 리듀서 작성하기
import produce from 'immer'
const person = { name: 'mike', age: 22}
const newPerson = produce(person, draft => {
draft.age = 32
})
리듀서 작성 시 주의할 점: 순수 함수
- API 호출 등,, → 액션 생성자 함수나 미들웨어에서 하면 된다.
- createReducers함수를 사용하면 switch문보다 더 간결하게 작성 가능하다.
6.2.4 스토어
- 스토어는 리덕스의 상탯값을 가지는 객체
- 스토어의 dispatch 메서드로 액션을 발생할 수 있다.
store.dispatch({ type: 'INCREMENT' })
6.3 데이터 종류별로 상탯값 나누기
6.3.1 상태값 나누기 예제를 위한 사전 작업
- friend state 파일 만들기
- timeline state 파일 만들기
- index.js 파일 만들기
- store.subscribe : action 처리가 끝날때마다 수행된다.
6.3.2 리듀서에서 공통 기능 분리하기
- 공통된 부분이 많기때문에 createItemsLogic.js 파일 만들기
- 이걸 사용하면 이렇게 간단해진다
- mergeReducers 파일 만들기
- timeline state 파일 수정
6.4 리액트 상탯값을 리덕스로 관리하기
- 리덕스는 리액트와 궁합이 잘 맞는다.
- 리액트 상탯값처럼 리덕스 상탯값도 불변 객체다. -> 값의 변경여부를 빠르게 확인할 수 있다.
6.4.1 react-redux 패키지 없이 직접 구현하기
- React Component 만들기
- mockData.js
forceUpdate() 동작
forceUpdate()
을 호출하면 곧바로 render()
가 호출된다. 즉 shouldComponentUpdate()
는 건너뛴다. 해당 메소드를 건너 뛰더라도, child components
의 life cycle method
는 정상적으로 다 호출된다. (즉 child component
의 shouldComponentUpdate()
는 호출된다.)
FriendMain component 개선하기
6.4.2 react-redux 패키지 사용하기
npm install react-redux
- Provider를 사용하여 store 관리하기
- Provider 컴포넌트는 전달받은 스토어의 subscribe 메서드를 호출해서 액션 처리가 끝날 때마다 알림을 받고, 컨텍스트 API를 사용해서 하위 컴포넌트로 리덕스의 상태값을 전달해준다.
- useSelector와 useDispatch
- react-redux 7 버전 이전 : connect HOC
- useSelector : store에 저장된 state를 가져오는 역할
- 리덕스 상태가 바뀌면 그 state를 사용하년 컴포넌트는 다시 렌더링 된다.
6.5 reselect 패키지로 선택자 함수 만들기
6.5.1 reselect 패키지 없이 구현해 보기
- 몇 살 이하의 친구를 몇명만 보여주자
- FriendMain.js 파일의 useSelector 함수를 수정한다
- timeline rerender를 할 때에도 state 값 다시 계산..
6.5.2 reselect 패키지 사용하기
- reselect의 memoization 기능
- data 값이 변하지 않으면 새롭게 데이터값을 연산하는 대신에 이전의 값을 사용하여 불필요한 연산을 막을 수 있다.
- createSelector 사용하기
- timeline rerender할 때 다시 계산 X
6.5.3 reselect에서 컴포넌트의 속성값 이용하기
- 선택자 함수는 상탯값 외에도 속성값을 입력으로 받아 각 컴포넌트에 특화된 값을 반환할 수 있다.
- 예시코드
- reselect에서 제공하는 메모이제이션 기능이 제대로 동작하지 않는다.
- 같은 선택자 함수를 다른 속성값으로 호출하기 때문에, 선택자 함수의 입장에서 연령제한 정보가 변경됨 → 매번 반복해서 연산을 수행한다.
6.5.4 컴포넌트 인스턴스별로 독립된 메모이제이션 적용하기
- 인스턴스별 독립된 메모이제이션 기능을 위해서는 선택자 함수도 여러 인스턴스로 만들어져야 한다.
- selector 함수 수정
- useMemo를 사용
6.6 리덕스 사가를 이용한 비동기 액션 처리
- API 호출을 통해서 서버로부터 데이터를 받아오고 상태값을 비동기로 처리하는 경우
6.6.1 리덕스 사가 시작하기
6.6.2 여러 개의 액션이 협업하는 사가 함수
- 다수의 액션을 하나의 사가 함수에서 사용할 수 있다.
function *loginFLow() {
while (true) {
const { id, password } = yield take(types.LOGIN)
const userInfo = yield call(callApiLogin, id, password)
yield put(types.SET_USER_INFO, userInfo)
yield take(types.LOGOUT)
yield call(callApiLogout, id)
yield call(types.SET_USER_INFO, null)
}
}
6.6.3 사가 함수의 예외 처리
6.6.4 리덕스 사가로 디바운스 구현하기
6.6.5 사가 함수 테스트하기
npm install @redux-saga/testing-utils
나의 깨달음 🤯
- 북마크를 저장하기 위해서 redux를 통한 상태값을 만들었고, 북마크 추가/삭제 와 같은 Action에서 로컬 스토리지 값을 변경하는 부수적인 일을 하게 됨
- 순수함수가 아니라서 테스트하기 힘들고, 고민중이었다..
- 로컬스토리지에 리덕스 상태값 저장하기
이런식으로 부수적인 것은 미들웨어 또는 subscribe 함수를 사용해서 처리해야겠다.
반응형
'CS > React' 카테고리의 다른 글
[React] 클래스형 컴포넌트의 생명 주기 메서드 (0) | 2021.10.21 |
---|