개발자
류준열
훅, 컴포넌트 밖에서 사용가능한 toast 유틸 만들기
React에서 useToast()를 커스텀 훅으로 만들어쓰고 있었다.
const toast = useToast(); toast({ type: "success", content: "저장되었습니다!", });
useToast 훅의 문제점
혹은 컴포넌트 내부에서만 호출 할 수 있다는 제약때문에 React 외부에서는 토스트를 띄울 수 없다.
이때의 문제점은 아래와 같이 axios intercepter 내부의 토큰만료 안내를 할 때는 브라우저 alert를 사용해야한다는 것이다.
axios.interceptors.response.use(
(res) => res,
async (error: AuthAxiosError) => {
...
const isTokenExpired =
status === 401
if (isTokenExpired && error.config.url === REFRESH_API_URL) {
...
alert("세션이 만료되어 로그인 페이지로 이동합니다.");
logout();
...
}
},
);
우리팀의 제품은 일관된 UI를 지향하는데, React의 제약에 체념한 상태였다.
하지만 'this는 메소드가 자신을 호출한 객체를 가리킨다' 는 성질을 이용하여 React 외부에서도 토스트를 띄울 수 있다.
전역 toast 유틸 객체 만들기
utils폴더안에 toast.ts를 다음과 같이 만들자.
// toast.ts
const toast = {
showToast: (newToastOption: ToastOptionType) => {
console.warn("ToastProvider가 아직 초기화되지 않았습니다.");
},
_setFunctions(add: (newToastOption: ToastOptionType) => void) {
this.showToast = add;
},
};
export default toast;
이 toast 객체는 React 바깥을 포함한 모든 전역에서 접근 가능하다. 초기에는 아무 기능도 없지만, 아래와 같이 Provider가 마운트되면서 내부 함수를 주입한다.
Provider안에서 함수 주입과 this 바인딩
export const Provider= ({...}:ToastProps) => {
...
const showToast = useToast();
useEffect(() => {
toast._setFunctions(showToast);
}, []);
...
return <>{children}</>
}
toast._setFunction
는 this가 해당 객체(toast
)를 가리킨다. 덕분에 toast.showToast에 내부 함수를 주입 할 수 있다.
사용방식
// utils/handleError.ts
import toast from "@/utils/toast";
export function handleError(message: string) {
toast.showToast({
type: "error",
content: `에러 발생: ${message}`,
});
}
정리
React 커스텀 훅은 범위에 제한이 있다. 그 한계를 벗아나기 위해서는 this 바인딩을 활용하는 것이 좋은 해결책이 될 수 있다.
이런 패턴은 toast뿐 아니라, 전역 알림, 로딩 처리등 모든 컴포넌트에 확장할 수 있다.
이 패턴을 팀원들에게 공유하여 모달, alert 등에 적용했고 컴포넌트 호출을 메서드로 처리하여 개발 생산성을 높힐 수 있었다.