리덕스는 리액트의 상태 관리 라이브러리이다
16-1. 개념 정리
16-1-1. 액션
상태에 어떤 변화가 필요하면 액션이 발생한다 이 액션은 객체로 표현되고 액션 객체는 다음과 같은 형식으로 이루어져 있다
{
type: 'TOGGLE_VALUE'
}
액션 객체는 위 처럼 type 필드를 반드시 가지고 있어야한다 이 type이 액션 객체의 이름이된다
16-1-2. 액션 생성 함수
말 그대로 액션 객체를 만들어주는 함수이다
function addTodo(data) {
return {
type: 'ADD_TODO',
data
};
}
액션 객체를 매번 직접 작성하게되면 실수할 가능성이 있기 때문에 함수로 틀을 만들어 둔 뒤 생성을 관리한다
16-1-3. 리듀서
리듀서는 변화를 일으키는 함수다
액션을 만들어서 발생시키면 리듀서가 현재 상태와 액션 객체를 받아온다
그 뒤에 액션이 지시하는대로 상태를 생성해서 반환한다
const initialState = {
counter:1
};
function reducer(state = initialState, action){
switch (action.type) {
case INCREASE :
return {
counter : state.counter +1
};
default :
return state;
}
}
16-1-4. 스토어
프로젝트에 리덕스를 적용하기 위해 스토어를 만든다
하나의 프로젝트에 하나의 스토어만 가질 수 있으며 스토어 안에는 현재 애플리케이션 상태와 리듀서 그리고 내장 함수들을 가지고 있다
16-1-5. 디스패치
디스패치는 스토어의 내장 함수 중 하나이다
디스패치는 액션을 발생시키는데 이 디스패치는 useReducer에서 사용한 것 과 같이
dispatch(action);
액션 객체를 파라미터로 넣어서 호출한다
이렇게 호출하면 액션이 발생하기 때문에 스토어에서 리듀서 함수를 실행시키고 리듀서는 다시 액션과 상태 값을 가져가서 변화를 만들어내는 것이다
16-1-6. 구독
구독도 스토어의 내장 함수 중에 하나다
subscribe 함수 안에 리스너 함수를 파라미터로 넣어서 호출해주면 이 리스너 함수가 액션이 디스패치되어 상태가 업데이트될 때마다 호출된다
얘는 뭔소린지 모르겠다 밑에서 실습하다 보면 알 수 있을듯
const listener = ()=>{
console.log('상태가 업데이트됨');
}
const unsubscribe = store.subscribe(listener);
unsubscribe();
이런식으로 사용한다고 한다
subscribe
store.subscribe(listener);
이렇게만 해 주어도 프로젝트에서 상태의 변화가 일어날 때 listener함수가 실행된다
const unsubscribe = store.subscribe(listener); //상태변화에 따라 listener가 실행됨
unsubscribe(); // 이제부터 상태변화에 따라 listener가 실행되지 않음
하지만 이렇게 subscribe을 할당해 줄 때 변수에 담아두면 차후 구독을 해제할 때 사용할 수 있다
16-2. 리액트 없이 쓰는 리덕스
리덕스는 리액트에 종속되는 라이브러리가 아니다 그렇기 때문에 다른 라이브러리나 프레임워크와 함께 사용할 수 있는데
우선 parcel을 이용해서 간단한 바닐라 자바스크립트와 리덕스를 사용한 프로젝트를 만들며 작동 원리를 익혀보자
<!DOCTYPE html>
<html lang="en">
<head>
<link rel="stylesheet" href="index.css">
<meta charset="UTF-8">
<title>vanilla js</title>
</head>
<body>
<div class="toggle"></div>
<hr>
<h1>0</h1>
<button id="increase">+1</button>
<button id="decrease">+1</button>
<script src="index.js"></script>
</body>
</html>
html, css의 구성은 위와 같다
16-2-1. 액션 타입과 액션 생성 함수 정의
프로젝트의 상태에 변화를 일으키는 것을 액션이라고 한다
액션의 이름은 대문자의 문자열 형태로 작성하며 고유해야한다
const divToggle = document.querySelector('.toggle');
const counter = document.querySelector('h1');
const btnIncrease = document.querySelector('#increase');
const btnDecrease = document.querySelector('#decrease');
const TOGGLE_SWITCH = 'TOGGLE_SWITCH';
const INCREASE = 'INCREASE';
const DECREASE = 'DECREASE';
위에서 생성한 액션 이름들을 이용하여 액션 객체를 만드는 액션 생성 함수를 작성해 보자
const toggleSwitch = ()=>({type:TOGGLE_SWITCH});
const increase = (difference)=>({type:INCREASE, difference});
const decrease = ()=>({type:DECREASE});
액션 객체는 반드시 type값을 가지고 있어야 한다
16-2-2. 초깃값 설정
프로젝트에서 사용할 초깃값을 설정하는데 이 때 초깃값의 형태는 자유이다
const initialState = {
toggle : false,
counter : 0,
};
16-2-3. 리듀서 함수 정의
리듀서는 변화를 일으키는 함수로 위에서 만들어준 action과 프로젝트의 상태값을 받아온다
function reducer(state = initialState, action){
switch (action.type){
case TOGGLE_SWITCH :
return {...state, toggle: !state.toggle};
case INCREASE :
return {...state, counter: action.counter + action.difference};
case DECREASE :
return {...state, counter: state.counter-1};
default :
return state;
}
}
제일 처음 reducer함수가 호출될 경우에는 state의 값이 undefine이기 때문에 그 때를 위해서 initialState를 파라미터에 기본값으로 설정해주었다
16-2-4. 스토어 만들기
스토어를 만들 때는 creatStore함수를 사용한다
const store = createStore(reducer);
스토어 함수를 만들 때 파라미터로 리듀서 함수를 넣어 주어야 한다
16-2-5. render 함수 만들기
내가 만들 render함수는 상태가 변경될 때마다 호출되며 리액트의 render와는 다르게 html을 사용하여 만들어진 UI의 속성을 상태에 따라 변경한다
const render = ()=>{
const state = store.getState();
if(state.toggle) divToggle.classList.toggle('active');
counter.innerText = state.counter;
}
render();
16-2-6. 구독하기
스토어의 상태가 바뀔 때 마다 방금 만들어준 render함수가 호출되도록 해 줄 건데 이 작업은 스토어의 내장 함수인 subscribe을 사용한다
subscribe 함수는 파라미터로 함수 형태의 값을 전달 받는다
store.subscribe(render);
16-2-7. 액션 발생시키기
액션을 발생시키는 것을 디스패치라고 하고 스토어의 내장 함수 dispatch를 사용해서 발생시킬 수 있다
파라미터로는 액션 객체를 받아서 위에서 설명한대로 작동하게 된다
divToggle.onclick = ()=>{
store.dispatch(toggleSwitch());
};
btnIncrease.onclick = ()=>{
store.dispatch(increase(1));
};
btnDecrease.onclick = ()=>{
store.dispatch(decrease());
};
각각의 클릭 이벤트가 발생하면 액션을 발생시켜서 리듀스 함수가 실행되고 스토어의 상태값이 바뀌기 때문에 subscribe 함수로 구독해 두었던 render함수가 실행되어서 바뀐 상태값에 따라 화면이 렌더링된다.
16-3. 리덕스의 세 가지 규칙
16-3-1. 단일 스토어
하나의 프로젝트에는 하나의 스토어만 가질 수 있다고 했지만 사실 여러 개의 스토어를 사용하는 것도 가능하다
특정 상태값의 업데이트가 너무 빈번하게 일어나면 완전히 분리시켜서 따로 스토어를 만들 수도 있지만 상태 관리가 복잡해질 수 있기 때문에 권장하지 않는다
16-3-2. 읽기 전용 상태
리액트에서 setState를 이용해서 state를 업데이트 하는 이유와 같다
새로운 객체를 생성해서 업데이트해 주어야 이전 객체와 비교(얕은 비교)를 할 때 더 나은 성능을 얻을 수 있기 때문
16-3-3. 리듀스는 순수한 함수
변화를 일으키는 리듀서 함수는 순수 함수이다 동일한 파라미터가 들어가면 항상 동일한 결과 값이 나와야하는 것
그래서 리듀스 함수 내부에서 변화할 수 있는 값이 들어가선 안된다 (ex: 랜덤 값 생성, 네트워크 요청..)
'React > 리액트를 다루는 기술' 카테고리의 다른 글
18. 리덕스 미들웨어를 통한 비동기 작업 관리 (0) | 2021.02.19 |
---|---|
17. 리덕스를 사용하여 리액트 애플리케이션 상태 관리하기 (0) | 2021.02.12 |
15. Context API (0) | 2021.02.10 |
14. 외부 API를 연동하여 뉴스 뷰어 만들기 (0) | 2021.02.08 |
13. 리액트 라우터로 SPA 개발하기 (0) | 2021.02.06 |