[typescript] Redux 상태 관리에서의 타입스크립트 디자인 패턴

Redux는 React 애플리케이션에서 상태를 효과적으로 관리하기 위한 라이브러리로 널리 사용되고 있습니다. 이 글에서는 Redux를 타입스크립트로 사용할 때 유용한 디자인 패턴에 대해 알아보겠습니다.

1. 액션(Action)과 상태(State)의 타입 정의

Redux에서는 액션과 상태의 타입을 명확히 정의하는 것이 중요합니다. 액션과 상태의 구조를 명확히 정의하면 코드의 가독성을 높일 뿐만 아니라 타입 에러를 줄일 수 있습니다.

// 액션의 타입 정의
type Action = {
  type: string;
  payload?: any;
}

// 상태의 타입 정의
type State = {
  count: number;
  loading: boolean;
}

2. 리듀서(Reducer)의 타입 정의

리듀서는 상태와 액션을 받아 새로운 상태를 반환하는 함수입니다. 타입스크립트에서는 리듀서의 타입을 명시하면 리듀서 함수 내에서 상태와 액션의 타입을 정확히 추론할 수 있습니다.

const reducer = (state: State, action: Action): State => {
  switch (action.type) {
    case 'INCREMENT':
      return { ...state, count: state.count + 1 };
    case 'DECREMENT':
      return { ...state, count: state.count - 1 };
    default:
      return state;
  }
}

3. 컨테이너(Container)와 프레젠테이션(Representation) 컴포넌트의 분리

타입스크립트에서는 컨테이너와 프레젠테이션 컴포넌트를 분리하여 각 컴포넌트의 역할을 명확히 정의하는 것이 중요합니다. 이를 통해 컴포넌트 간의 의존성을 줄이고 유닛 테스트를 용이하게 할 수 있습니다.

// 컨테이너 컴포넌트
const CounterContainer: React.FC = () => {
  const count = useSelector((state: State) => state.count);
  const dispatch = useDispatch();
  
  const handleIncrement = () => {
    dispatch({ type: 'INCREMENT' });
  }
  
  // ... 

  return <Counter count={count} onIncrement={handleIncrement} />;
}

// 프레젠테이션 컴포넌트
type CounterProps = {
  count: number;
  onIncrement: () => void;
  // ...
}

const Counter: React.FC<CounterProps> = ({ count, onIncrement }) => {
  return (
    <div>
      <p>{count}</p>
      <button onClick={onIncrement}>Increment</button>
      {/* ... */}
    </div>
  );
}

타입스크립트를 사용하면 Redux를 보다 안정적으로 사용할 수 있습니다. 액션과 상태의 타입을 명확히 정의하고, 리듀서 함수의 타입을 명시함으로써 코드의 안정성을 높일 수 있습니다. 또한, 컨테이너와 프레젠테이션 컴포넌트를 분리하여 코드의 유지보수성을 향상시킬 수 있습니다.

참고 자료