💡 이 챕터에서 배우는 내용
- Redux가 무엇이고 사용하는 이유
- 중요 Redux 용어와 개념들
- Redux 앱에서 data가 흐르는 방식
Redux는 "actions"라고 불리는 이벤트를 사용하여 애플리케이션 상태를 관리하고 업데이트하기 위한 패턴 및 라이브러리입니다.
(1) React-Redux
(2) Redux-Toolkit
(3) Redux DevTools Extension
React Counter 컴포넌트
function Counter() {
// State: 카운터 값
const [counter, setCounter] = useState(0);
// Action: 어떤 일이 일어나면 상태를 업데이트하는 코드
const increment = () => {
setCounter(prevCounter => prevCounter + 1);
};
// View: UI 정의
return (
<div>
Value: {counter} <button onClick={icrement}>Increment</button>
</div>
)
}
불변성은 절대 변할 수 없다는 것을 의미합니다.
자바스크립트 객체와 배열은 기본적으로 모두 변할 수 있습니다.
만약 객체나 배열을 생성하다면, 해당 필드의 내용을 바꿀 수 있습니다.
const obj = { a: 1, b: 2 };
// 바깥에서는 여전히 똑같은 객체이지만, 내용은 변경됨
obj.b = 3;
const arr = ['a', 'b'];
// 똑같은 방법으로, 배열의 내용 변경 가능
arr.push('c');
arr[1] = 'd';
이를 객체 또는 배열 변경이라고 합니다.
값을 불변하게 업데이트하기 위해서는 객체와 배열의 복사본을 만들고 복사본을 수정해야 합니다.
const obj = {
a: {
// obj.a.c를 안전하게 업데이트하기 위해 각각을 복사해야 함
c: 3
},
b: 2
};
const obj = {
// obj 복사
...obj,
// a 오버라이딩
a: {
// obj.a 복사
...obj.a,
// c 오버라이딩
c: 42
}
}
const arr = ['a', 'b'];
// arr의 새로운 복사본을 만들고 끝에 "c" 추가
const arr2 = arr.concat('c');
// 또는 원본 배열의 복사본 생성
const arr3 = arr.slice();
// 그리고 복사본 변경
arr3.push('3');
리덕스는 모든 상태가 불변적으로 업데이트될 것이라고 예상합니다.
type
필드를 가진 순수 자바스크립트 객체입니다.type
필드는 문자열이어야 합니다. 보통 "domain/eventName"
처럼 작성합니다.payload
라고 불리는 필드에 넣습니다.const addTodoAction = {
type: 'todos/todoAdded',
payload: 'Buy milk'
};
const addTodo = text => {
return {
type: 'todos/todoAdded',
payload: text
};
};
리듀서 (Reducers)
리듀서는 현재 상태와 액션 객체를 받고, 필요에 따라 어떻게 상태를 업데이트할 것인지 결정하고, 새로운 상태를 반환하는 함수입니다.
(state, action) => newState
리듀서는 받아온 액션(이벤트) 타입을 기반으로 이벤트 처리하는 이벤트 리스너로 생각할 수 있습니다.
리듀서는 특정한 규칙들을 따라야 합니다.
state
와 action
인자를 기반으로 한 새로운 상태 값만 계산합니다.리듀서 함수의 로직 안에서는 일반적으로 다음의 단계를 따라갑니다.
const initialState = { value: 0 };
function cunterReducer(state = initialState, action) {
// 리듀서가 이 액션과 관련있는지 확인
if (action.type === 'counter/increment') {
// 관련있다면, 상태의 복사본을 만듦
return {
...state,
// 새로운 값의 복사본 업데이트
value: state.value + 1
};
}
// 그렇지 않으면, 변경되지 않은 기존의 상태를 반환
return state;
}
리듀서는 새로운 상태 (if/else, switch문, 반복문 등)를 결정하기 위해 내부의 모든 로직을 사용할 수 있습니다.
스토어 (Store)
현재 Redux 애플리케이션 상태는 스토어라고 불리는 객체 안에 있습니다.
스토어는 리듀서를 전달하여 생성되고, 현재 상태 값을 반환하는 getState
메서드를 가지고 있습니다.
import { configureStore } from '@reduxjs/toolkit';
const store = configureStore({ reducer: counterReducer });
console.log(store.getState()); // {value: 0}
디스패치 (Dispatch)
리덕스 스토어는 dispatch
라고 불리는 메서드를 가지고 있습니다.
상태를 업데이트할 수 있는 유일한 방법은 store.dispatch()
를 호출하고 액션 객체를 전달하는 것입니다.
스토어는 리듀서 함수를 실행하고 내부에 새로운 상태 값을 저장하고, getState()
를 호출하여 업데이트된 값을 검색할 수 있습니다.
store.dispatch({ type: 'counter/increment' });
console.log(store.getState()); // {value: 1}
액션을 디스패치하는 것을 애플리케이션 상에서 "이벤트가 발생"하는 것처럼 생각할 수 있습니다.
올바른 액션을 디스패치 하기 위해 일반적으로 액션 생성자를 호출합니다.
const increment = () => {
return {
type: 'counter/increment'
};
};
store.dispatch(increment());
console.log(store.getState()); // {value: 2}
선택자 (Selectors)
const selectCounterValue = state => state.value;
const currentValue = selectCounterValue(store.getState());
console.log(currentValue); // 2
dispatch({ type: 'counter/increment' })
처럼 리덕스 스토어에 액션을 디스패치합니다.type
필드의 순수 객체이고, 앱에서 "어떤 일이 일어났는지"를 설명합니다.출처
🔗 공식 문서: https://ko.redux.js.org/tutorials/essentials/part-1-overview-concepts
🔗 Github: https://github.com/chaevivin/Front-end_study/blob/main/Redux/Redux_Overview_and_Concepts.md
더 자세하게 정리되어 있고, 번역된 문서를 보고싶다면 Github에서 제가 작성한 문서를 확인하세요.