가상의 향수 쇼핑몰을 제작하는 프로젝트에서, 나는 Redux 라이브러리를 상태 관리 용도로 적용하였다. 그런데 Redux는 상태 관리 라이브러리면서, 한편으로는 하나의 프론트엔드 아키텍처이기도 하다.
액션(Action): 상태를 변화시키기 위한 정보를 담고 있는 객체로, 'type' 필드를 반드시 가지고 있어야 한다.
리듀서(Reducer): 현재 상태와 액션을 인자로 받아, 새로운 상태를 반환하는 순수 함수.
스토어(Store): 애플리케이션의 전체 상태를 보관하는 객체로, 리듀서와 함께 생성되고, 애플리케이션 내에서 단 하나만 존재해야 한다.
뷰(View): React 컴포넌트로 구성되며, Redux 스토어의 상태를 표시하고 사용자의 상호작용에 반응한다.
import { useEffect } from 'react';
import { useDispatch, useSelector } from 'react-redux';
import { setTheme } from '../redux/slices/uiSlice';
import { RootState } from '../redux/store';
export const useChangeTheme = () => {
const dispatch = useDispatch();
const theme = useSelector((state: RootState) => state.ui.theme);
useEffect(() => {
localStorage.setItem('theme', theme);
}, [theme]);
return (newTheme: 'light' | 'dark') => {
dispatch(setTheme(newTheme));
};
};
그런데 내가 구현중인 언어/테마 변경 기능의 경우, 커스텀 훅을 사용하는 방식으로 구현하였다. 얼핏 보자면 커스텀 훅은 Redux 구조의 어디에도 포함되지 않는데, 그렇다면 나는 아키텍처의 원칙을 위반한 것인가?
그렇지는 않다. 커스텀 훅은 액션 디스패치, 사이드 이펙트 관리, 로직의 재사용과 캡슐화 등의 기능을 대신 수행해줄 수 있다. 어찌보면 미들웨어의 기능을 일부 수행하고 있다고 볼 수도 있다. 로컬 스토리지와의 상태 동기화라는 부가적인 작업을 수행하고 있기 때문.
그렇다고 해도 커스텀 훅을 마구잡이로 사용하라는 뜻은 아니다. Redux 아키텍처 원칙에 위반되지 않는 한도 내에서는 자유롭게 사용해도 된다는 뜻이다.
상태 변경의 중앙집중화: 모든 상태 변경은 Redux 스토어를 통해 이루어져야 한다. 직접 컴포넌트의 상태를 변경하는 것이 아니라, 액션을 통해 스토어의 상태를 변경해야 한다.
사이드 이펙트의 일관된 관리: 사이드 이펙트는 Redux 미들웨어나 커스텀 훅을 통해 일관되게 관리되어야 하며, 이를 통해 예측 가능한 상태 변경을 유지해야 한다.
이런 부분만 조심한다면. 커스텀 훅은 Redux 아키텍처의 원칙을 준수하면서도 개발자에게 유연성을 제공하고, 코드의 재사용성을 향상시키는 방법을 제공하는. 아키텍처를 보완하고 강화하는 수단이 될 수 있다.