redux 개요
부모와 자식간에 통신이 그 단계가 길어지게 되면 여러번 통신을 하게 된다. redux를 사용하게 되면 store에 그 데이터를 저장하고 읽을 수 있으므로 여러단계의 통신을 한단계로 줄일수 있게 된다.
redux가 없는 구조
redux가 있는 구조
+ single source of truth:상태를 저장하는 store는 단 한개 존재한다.
+ state를 변경(mutation)하는 유일한 방법은 액션을 보내는(dispatch)것이다. state를 직접 변경해서는 안된다.
+ reducer는 순수 함수로서 action과 state를 받아서 새로운 state를 만든다
setup & install
create-react-app 으로 별도의 프로젝트를 하나 생성한다.
그리고 redux 모듈을 설치한다. redux 는 리액트와 관련이 없는 순수한 3rd party 라이브러리이다. 다음 커리큐럼에서는 redux를 react에 적용한 라이브러리인 react-redux를 설치할 것이다. 여기서는 일단 redux만 설치한다.
1 2 |
npx create-react-app redux-tutorial npm install --save redux |
store 생성
store를 만들고 출력해보자.
1 2 3 4 5 6 |
import {createStore} from 'redux'; ... const store = createStore(); console.log(store); |
Expected the reducer to be a function 이라는 에러가 발생할 것이다. store가 처음 생성시 reducer 펑션을 실행한다. action이 dispatch 되면 action과 state를 입력파라메터로 새로운 state를 생성하지만 최초에 store를 생성시에는 action 없이 reducer를 실행해서 state를 생성, 즉 초기화한다.
reducer 생성
json 객체를 리턴하는 단순한 reducer 를 만들자.
1 2 3 4 5 6 7 |
const userReducer = () => { return { name: 'Tom' }; } const store = createStore(userReducer); console.log(store, store.getState()); |
콘솔화면에 store가 dispatch, subscribe, getState, replaceReducer 등 여러가지 메서드가 보일것이다. store.getState()를 출력하면 reducer 펑션을 실행하고 리턴된 { name: ‘Tom’ } 라는 초기 state를 볼 수 있다.
action dispatch
액션은 객체이다. 액션을 dispatch 해보자. 먼저, reducer에 state, action 두가지 파라메터를 추가하고 로그도 추가한다.
그 다음에 type과 payload를 갖고 있는 action을 만든다.
그리고 이제 action을 dispatch 한다.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 |
const userReducer = (state, action) => { console.log(action); return { name: 'Tom' }; } const store = createStore(userReducer); console.log(store, store.getState()); const action = { type: 'UPDATE_USER', payload: 'Jane' } store.dispatch(action); |
createStore로 처음에 store 생성시 reducer가 init 액션으로 한번 불리고 dispatch시에 reducer가 다시 호출된다.
reducer에 action type이 UPDATE_USER일 경우에 payload의 Jane을 리턴하도록 한다.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 |
const userReducer = (state, action) => { console.log(action); if (action.type === 'UPDATE_USER') { return { ...state, name: action.payload}; } return state; } const store = createStore(userReducer); console.log(store, store.getState()); const action = { type: 'UPDATE_USER', payload: 'Jane' } store.dispatch(action); console.log(store.getState()); |
콘솔에 찍힌 로그를 보면 state가 { name: ‘Jane’ } 으로 바뀐걸 알 수 있다.
subscribe
상태가 변경되면 변경된 상태값을 읽을 수 있게 subscribe를 해보자.
1 2 3 |
store.subscribe(() => console.log(store.getState())); store.dispatch(action); |
로그를 보면 state가 변경될 때마다 항상 호출되는 것을 알 수 있다.
redux devtools 설치
크롬에서 redux devtools를 설치한다.
devtools만 설치한다고 디버깅이 되지 않는다. store를 생성시 두번째 파라메터로 아래와 같이 넘겨주어야 한다.
1 |
const store = createStore(reducer, window.__REDUX_DEVTOOLS_EXTENSION__ && window.__REDUX_DEVTOOLS_EXTENSION__()); |
디버깅 툴에서 action과 state를 확인해보자.
counter reducer 추가
reducer는 보통 여러개의 모듈로 이루어져 있는 경우가 많다.
counter reducer 를 추가한다. 그리고 두개의 reducer를 combineReducers를 이용해서 하나로 묶는다.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 |
import {combineReducers, createStore} from 'redux'; const userReducer = (state, action) => { console.log(action); if (action.type === 'UPDATE_USER') { return { ...state, name: action.payload}; } return state; } const counterReducer = (state = initialState, action) => { switch(action.type) { case 'INCREASE': return state + 1; case 'DECREASE': return state - 1; default: return state; } } const allReducer = combineReducers({ count: counterReducer, user: userReducer }) const store = createStore(allReducers, window.__REDUX_DEVTOOLS_EXTENSION__ && window.__REDUX_DEVTOOLS_EXTENSION__()); |
+ Q: store를 생성후 store.getState()의 결과는 무엇인가?
1 2 3 4 |
{ count: 0, user: { name: 'Tom' } } |
+ Q: count 의 값을 0에서 1로 변경할려면 어떻게 해야 하는가?
store의 state를 직접 변경할 수는 없다. state를 변경하기 위해서는 액션을 디스패치 하는 방법밖에 없다. reducer에 INCREASE 일 경우 1 증가하는 reducer를 만들어 놓았으므로 아래와 같이 액션을 디스패치 한다.
1 2 3 4 5 |
const action = { type: 'INCREASE' } store.dispatch(action); |
+ Q: 위와 같이 액션을 dispatch 후 store.getState()의 출력은 무엇인가?
1 2 3 4 |
{ count: 1, user: { name: 'Tom' } } |
요약
+ redux는 프레임웍이다.
+ Publisher – Subscriber 구조로 action을 dispatch 하는것은 publish에 해당하고 publish 전에 변경된 상태를 읽을 필요가 있으면 먼저 subscribe 해야 한다.
+ store 는 single source를 갖고 있다.
+ store가 처음 생성되면 reducer를 실행해서 state를 초기화 한다.
+ action type 은 스트링이다.
+ action은 객체이다.
+ action creator 는 액션을 생성하는 함수이다.
+ reducer는 순수한 펑션으로 이루어져 있다.
+ action을 dispatch 하면 store에 reducer가 실행되고 reducer는 state, action을 입력으로 받아서 새로운 state를 생성한다.
+ store의 state를 바꾸는 방법은 action을 dispatch하는 방법밖에 없다.