# 239 [udemy React 완벽 가이드 노트] Redux의 작동방식 core foundation
리덕스의 작동방식
Redux는 중앙 데이터 저장소다.
여기에 애플리케이션의 모든 state를 저장하며,
두개 이상의 저장소를 가지지 않는다.
관리가 어렵지 않은가?
아니다. 저장소를 직접 관리할 필요가 없다.
중앙 저장소에 대한 구독을 설정하고
컴포넌트 안에서 사용하면
데이터의 변경을 컴포넌트에서 인지해 UI를 업데이트 하게 된다.
데이터 변경 방법
컴포넌트는 데이터를 직접 조작하지 않는다.
그대신 리듀서를 사용한다.
리듀서 함수는 데이터 저장소의 데이터를 변경하는 일을 한다.
useReducer 훅과는 다르다.
Reducer Function
입력을 받아서 입력을 변환하고 줄이는 함수.
입력을 변환해서 새로운 출력, 새로운 결과를 내보낸다
useReducer는 훅이 사용하고, Reducer function은 리덕스도 사용한다.
저장도 데이터의 업데이트를 담당한다.
Action
컴포넌트가 액션을 발송(dispatch)
액션은 자바스크립트 객체
리듀서가 수행해야 할 작업을 설명함
리덕스가 이action을 reducer function으로 전달하게 됨
그러면 원하는 작업에 대한 설명을 읽고
그 작업을 리듀서가 수행하게 된다.
리덕스의 핵심 개념
빈 프로젝트 폴더에 새 파일을 만든다
해당 폴더의 경로로 가서 npm init을 한다.
npm init
그리고
npm install redux
을 한다
redux import 하기
const redux = require('redux');
리덕스 패키지로부터 리덕스를 임포트 해주는 구문
지금은 node.js이기 때문에 react 구문과는 조금 다르다.
필요한것:
저장소store
리듀서 함수 Reducer function
액션Action
저장소를 구독하기 위한 설정 코드 등
Store 만들기
store를 만들어 변수에 저장한다.
store는 데이터를 관리해야 한다.
data는 reducer function에 의해 결정된다.
reducer function은 새로운 state 스냅샷을 생성한다.
reducer는 액션이 도착할 때마다 새로운 state 스냅샷을 생성 한다.
처음 아래의 코드를 실행할 때 리듀서가 실행되고
기본 액션을 할 것이다. (초기상태를 생성 한다)
const store = redux.createStore()
reducer function 추가하기
reducer function은 기본 javascript function이지만
redux library에 의해 호출될 것이다.
reducer function의 inputs : Old State 와 Dispatched Action reducer function의 output : New State Object (새로운 상태 객체) |
reducer function은 순수한 함수여야 한다.
동일한 입력(same input) 을 넣으면 동일한 산출물 (same output) 이 있어야 한다.
reducer function안에서는 어떠한 부수적 효과side effects도 없어야 한다.
(HTTP 요청전송, 로컬 저장소에 기록, 로컬 저장소에서 무언가를 가져오기 등)
reducer는 redux가 제공하는 입력을 취하고 예상된 출력물인
새로운 state object를 생성하는 순수한 함수가 되어야 한다.
Reducer는 redux library에 의해 실행되며 state, action을 기본값으로서 받게 된다.
const counterReducer = (state, action) => {
Reducer는 새로운 state를 return 하며, 기존의 state를 대체할 것이다.
객체가 될 수도 있지만 어떤 유형도 상관은 없다
그러나 보통 여러개의 state이므로 객체를 사용한다
const counterReducer = (state, action) => {
return {
counter: state.counter + 1,
}
}
이 reducer 함수는 counter가 1씩 늘어나는 객체를
항상 반환하게 될 것이다.
자동으로 받는 기존 state를 참조하고,
state에 저장되어있는 기존의 counter값에 액세스 하고,
새롭게 return하는 counter 값으로서 기존 state.counter에 1을 더한다.
이 counterReducer을 createStore 함수로 전달해준다.
store가 어떤 reducer가 변경을 가했는지 알아야 하기 때문이다.
const store = redux.createStore(counterReducer);
store와 작업하는 건 reducer이기 때문이다.
그래서 store는 데이터를 어떤 reducer 함수가 변경했는지 알아야 한다.
Subscription
subscription하는 함수를 변수에 저장해주고
store에서 getState를 호출한다.
getState는 create store로 만들어진, 저장소store에서 사용할 수 있는 메서드다
그리고 이것을 통해 업데이트 후에 최신 state스냅샷을 제공할 것이다.
이 subscription함수는 state의 변경 시마다 트리거 될 것이다.
그러면 getState 메서드로 변경된 최신 state를 얻을 수 있게 된다.
const counterSubscriber = () => {
const latestState = store.getState();
이제 리덕스가 구독 함수를 인식하도록 하고,
상태가 변경될 때마다 이 함수를 실행하라고 말해줘야 한다.
store.subscribe();
store로 가서 subscribe 메서드를 실행한다.
이 메서드는 subscriber 함수를 취한다.
그러면 리덕스는 데이터와 저장소가 변경될 때마다 그걸 실행해 줄 것이다.
store.subscribe(counterSubscriber);
실행은 하지 않는다. 가리킬 뿐이다.
리덕스가 실행할 것이다.
이제 터미널에서 실행해 보자.
node .\redux-demo.js
오류가 떴다.
우리는 store를 만들었고
이 저장소에 필요한 counterReducer가 있다.
그 reducer안에서 counter: state.counter+1 이 들은 객체를 return 하는데
기존 state.counter에 1을 더해서 카운터를 새로 설정하는 것이다.
그런데 store가 초기화 될 때 기존의 state.counter가 정의된 바 없이 실행되기 때문에
default Value를 정해주도록 하자.
const counterReducer = (state = { counter: 0 }, action) => {
그러면 아무 오류가 뜨지 않는다.
그러나 어떤 것도 볼 수 없는데
action을 발송하지 않았기 때문이다.
const store = redux.createStore(counterReducer);
물론 이부분도 기본 액션이지만
구독을 트리거하는 액션은 아니다.
초기 상태를 보여주는 코드를 추가해보자.
console.log(store.getState());
그러면 다시 node를 터미널에서 실행해보면 아래와 같이 나온다.
그런데 객체안의 counter값이 1이다.
왜그럴까?
초기값이 0이고 처음 실행될 때 counter : state.counter + 1이 실행되어 1이 되었다.
그런데 console.log() 코드는 필요없으니 삭제한다.
Action
action을 만들어 dispatch 발송 해보도록 하자.
store.dispatch();
dispatch는 액션을 발송하는 메서드다.
액션은 자바스크립트 객체object다.
객체안의 type 은 식별자 역할을 하는 프로퍼티다.
type의 값은 문자열인데 식별 가능한 고유한 문자열로 해야 한다.
예를들어
store.dispatch({type: 'increment'});
이렇게 하고 redux-demo.js파일을 실행하면
위와 같이 나온다.