- 하나의 애플리케이션 안에는 하나의 스토어
- 상태는 읽기 전용
: 불변성을 유지해야 하는 이유는 내부적으로 데이터가 변경 되는 것을 감지하기 위하여 shallow equality 검사를 하기 때문- 변화를 일으키는 함수, 리듀서는 순수한 함수여야 한다.
: 리듀서 함수는 이전 상태와, 액션 객체를 파라미터로 받습니다.
: 이전의 상태는 절대로 건들이지 않고, 변화를 일으킨 새로운 상태 객체를 만들어서 반환합니다.
: 똑같은 파라미터로 호출된 리듀서 함수는 언제나 똑같은 결과값을 반환해야만 합니다.
동일한 인풋이라면 언제나 동일한 아웃풋이 있어야 한다.
일부 로직들 중에서는 실행 할 때마다 다른 결과값이 나타날 수도 있다. new Date(), 랜덤 숫자 생성, 혹은, 네트워크에 요청 등등.
그러한 작업은 결코 순수하지 않은 작업이므로, 리듀서 함수의 바깥에서 처리해줘야 한다. 이를 위해, 리덕스 미들웨어 를 사용하곤 한다.
npx create-react-app practice-redux npm install redux react-redux
리덕스 사용 정리
Redux의 구성 요소
Redux 사용
Redux 모듈화
rootReducer.js
import { combineReducers } from 'redux'; import subscriberReducer from './subscribers/reducer'; import viewsReducer from './views/reducer'; const rootReducer = combineReducers({ view: viewsReducer, subscribers: subscriberReducer, }); export default rootReducer;
npm install redux-logger
import { createStore, applyMiddleware } from 'redux';
import rootReducer from './rootReducer';
import { composeWithDevTools } from 'redux-devtools-extension';
// 미들웨어 logger
import logger from 'redux-logger';
import subscriberReducer from './subscribers/reducer';
// 미들웨어가 여러개일 때 배열에 넣어서 사용
const middleware = [logger];
// 두개의 reducer를 하나의 store로
// 미들웨어는 두번째 인자에
const store = createStore(
rootReducer,
composeWithDevTools(applyMiddleware(...middleware))
);
export default store;
리덕스에서 비동기 작업을 처리할 때는 redux-thunk라는 미들웨어를 많이 사용한다.
thunk 미들웨어는 객체 대신 함수를 생성하는 액션 생성함수를 작성 할 수 있도록 해준다.
npm install redux-thunk
비동기 액션 생산자는 리듀서로 연결되지 않고, 직접 dispatcher를 통해 스토어로 새로운 상태를 보내준다. 함수를 dispatch 할 때에는, 해당 함수에서 dispatch 와 getState 를 파라미터로 받아와주어야 한다.
thunk를 middleware에 추가해주면, action에서 dispatch를 리턴해 줄 수 있는 기능 사용이 가능해진다.
import { createStore, applyMiddleware } from 'redux';
import rootReducer from './rootReducer';
import { composeWithDevTools } from 'redux-devtools-extension';
import thunk from 'redux-thunk';
import logger from 'redux-logger';
import subscriberReducer from './subscribers/reducer';
const middleware = [logger, thunk];
const store = createStore(
rootReducer,
composeWithDevTools(applyMiddleware(...middleware))
);
export default store;
export const addSubscriber = () => {
return (dispatch, getState) => {
console.log(getState()); //-> {view: {…}, subscribers: {…}}
setTimeout(() => {
dispatch({ type: ADD_SUBSCRIBER });
}, 1000); // 1초 후에 dispatch 실행
};
};
<button onClick={() => dispatch(addSubscriber())}>구독</button>
action 함수에서 dispatch, getState 를 파라미터로 받게 한다면 스토어의 상태에 접근할 수 있다.
따라서, 현재의 스토어 상태의 값에 따라 액션이 dispatch 할지, 안할지를 결정할 수 있다.
즉, redux-thunk 는 일반 액션 생성자에 날개를 달아준다. 보통의 액션생성자는 그냥 하나의 액션객체를 생성 할 뿐이지만, redux-thunk 를 통해 만든 액션생성자는 그 내부에서 여러가지 작업을 할 수 있다. 이 곳에서 네트워크 요청도 할 수 있고, 여러번의 디스패치를 할 수도 있다.
npm install --save redux-devtools-extension
import { createStore, applyMiddleware } from 'redux';
import { composeWithDevTools } from 'redux-devtools-extension';
const middleware = [thunk];
const store = createStore(reducer, composeWithDevTools(
applyMiddleware(...middleware),
// other store enhancers if any
));