👩🔧 숫자를 증가시키거나 감소시키는 카운터 애플리케이션
// actions.ts
export const INCREASE = 'INCREMENT/DECREMENT';
액션 타입은 상수로 정의하고, 문자열 리터럴 타입으로 선언합니다.
// actions.ts
export interface IncreaseAction {
type: typeof INCREASE; // typeof "상수 문자열" -> ~type을 반환
count: number;
}
// 액션 타입들을 하나로 묶어서 Union 타입을 구성하기 위해 사용
export type CounterAction = IncreaseAction;
export const increaseCount = (count: number): IncreaseAction => ({
type: INCREASE,
count, // payload 필드
});
액션 크리에이터 함수를 작성하여 액션을 생성합니다. 액션 객체는 type 필드와 필요한 경우 추가적인 데이터를 가진 payload 필드로 구성됩니다.
INCREASE를 사용하여 타입을 제한하고, IncreaseAction 인터페이스로 액션의 타입을 지정합니다.
리덕스의 액션 타입을 정의할 때 상수로 문자열을 선언한 경우 typeof를 사용하여 타입의 안정성을 높일 수 있습니다.
스위치 문에서 action.type과 case의 타입이 정확히 일치하는지 확인할 수 있습니다. 따라서 action.type이 'INCREMENT/DECREMENT'가 아닌 다른 문자열을 갖게 된다면 컴파일러가 오류를 발생시킵니다.
액션 객체를 나타내는 인자입니다. 액션 객체는 상태를 변경하는 데 필요한 정보를 포함하고 있으며, 해당 객체는 최소한 type이라는 필드를 가져야 합니다.
const increaseCount = (count: number) => ({
type: INCREASE, // 액션의 타입
count, // 추가 데이터 (예: 증가량)
});
// store.ts
export interface RootState {
count: number;
}
// store.ts
import { INCREASE, CounterAction } from './actions';
// 초기값 설정
const initialState: RootState = {
count: 0,
};
// state: RootState -> 타입스크립트가 상태의 구조와 속성을 추론하고,
// 잘못된 타입의 값이 상태에 할당되는 것을 방지
const counterReducer = (state: RootState = initialState, action: CounterAction): RootState => {
// 앞의 RootState -> 첫 번째 매개변수 타입지정, 뒤 RootState -> RootState 타입의 객체
switch (action.type) {
case INCREASE:
// { ...현재값, 액션 }; -> 새로운 상태를 계산하고 반환
return { ...state, count: action.count }; // count : count 속성 업데이트
default:
return state;
}
};
export { RootState, counterReducer };
현재값을
스프레드(spread)연산자(...)를 사용하여 그대로 복제하기 때문에불변성을 유지합니다.
리듀서는 변화를 일으키는 함수입니다. 액션을 만들어 발생시키려면 리듀서가 현재 상태와 전달받은 액션 객체를 파라미터로 받아 옵니다. 그리고 두 값을 참고하여 새로운 상태로 반환해 줍니다.
리듀서 함수는 현재 상태(state)와 액션(action)을 매개변수로 받고, 새로운 상태를 반환합니다.
state
: 리듀서 함수가 현재 상태를 나타내는 인자입니다. 이 매개변수는 현재 상태를 변경하거나 새로운 상태를 반환하는 데 사용됩니다. 일반적으로 state 매개변수는 기본값을 가지며, 애플리케이션이 처음 실행될 때 이 기본값을 가진 상태로 초기화됩니다.
action
: action 매개변수를 통해 액션의 타입을 식별하고, 해당 액션에 따라 상태를 변경합니다.
const initialState = {
// 초기 상태를 정의합니다.
};
const reducerName = (state = initialState, action) => {
// 액션 타입에 따라 상태를 처리하고 변경한 새로운 상태를 반환합니다.
switch (action.type) {
case 'ACTION_TYPE_1':
// 처리 로직
return {
...state,
// 업데이트할 상태 속성들
};
case 'ACTION_TYPE_2':
// 처리 로직
return {
...state,
// 업데이트할 상태 속성들
};
default:
// 기본 동작 (액션이 처리되지 않을 때)
return state;
}
};
export default reducerName;
// store.ts
import { createStore } from 'redux';
import { counterReducer } from './store';
const store = createStore(counterReducer);
redux를 사용하기 위해서 store을 만듭니다. 1개의 프로젝트에는 1개의 store을 가질 수 있으며 store 안에는 현재 애플리케이션 상태와 reducer이 들어있습니다. createStore 함수를 사용하여 생성합니다.
루트 리듀서를 사용하는 경우, 여러 개의 리듀서를 결합합니다. 이는 프로젝트의 규모에 따라 다르며, 작은 프로젝트에서는 필요하지 않을 수 있습니다.
미들웨어를 적용하여 리덕스의 동작을 확장하거나 비동기 작업을 처리합니다. 미들웨어를 적용하는 방법은 다양합니다.
// App.tsx
import React from 'react';
import { Provider } from 'react-redux';
import Counter from './Counter';
const App: React.FC = () => {
return (
// 만든 store를 앱 상위에 넣어줍니다.
<Provider store={store}>
<Counter />
</Provider>
);
};
export default App;
울타리 역할을 하며 props로 store을 지정해줘야 합니다.
// Counter.tsx
import React from 'react';
import { useSelector, useDispatch } from 'react-redux';
import { RootState } from './store';
import { increaseCount } from './actions';
const Counter: React.FC = () => {
// store에 접근하여 state 가져오기
// useSelector의 콜백 함수로 RootState의 타입을 지정하여 상태의 타입을 정의
const count = useSelector((state: RootState) => state.count);
// dispatch를 사용하기 위한 준비
const dispatch = useDispatch();
const handleIncrement = () => {
// store에 있는 state 바꾸는 함수 실행
dispatch(increaseCount(count + 1));
};
const handleDecrement = () => {
dispatch(increaseCount(count - 1));
};
return (
<div>
<h2>Counter</h2>
<p>Count: {count}</p>
<button onClick={handleIncrement}>Increment</button>
<button onClick={handleDecrement}>Decrement</button>
</div>
);
};
export default Counter;
컴포넌트에서 리덕스 스토어의 상태를 읽거나 액션을 디스패치하여 상태를 업데이트합니다. useSelector 훅을 사용하여 상태를 읽고, useDispatch 훅을 사용하여 액션을 디스패치합니다.
디스패치는 스토어의 내장 함수 중 하나입니다. 쉽게 말해 액션을 발생시키는 역할을 합니다.
이 함수는 dispatch(action)과 같은 형태로 액션 객체를 파라미터로 넣어서 호출합니다. 이 함수가 호출되면 스토어는 리듀서 함수를 실행시켜서 새로운 상태를 만들어 줍니다.
Store의 상태를 쉽게 선택할 수 있게 하는 함수로 이를 통해 컴포넌트에서 필요한 상태를 쉽게 조회할 수 있습니다.
combineReducers는 Redux에서 사용되는 여러 개의 리듀서(reducer)를 하나로 결합하는 함수입니다.
글이 잘 정리되어 있네요. 감사합니다.