개발자
류준열

훅, 컴포넌트 밖에서 사용가능한 toast 유틸 만들기

React에서 useToast()를 커스텀 훅으로 만들어쓰고 있었다.

const { addToast } = useToast();

addToast({
  type: "success",
  content: "저장되었습니다!",
});

그런데 이러한 방식은 axios intercepter하여 토큰 만료시 갱신 처리하는 곳 등 훅, 컴포넌트 외부에서는 toast를 사용할 수 없는 단점이 있다.

전역 toast 유틸 객체 만들기


// toast.ts

const toast = {
  addToast: () => {
    console.warn("ToastProvider가 아직 초기화되지 않았습니다.");
  },
  removeToast: () => {
    console.warn("ToastProvider가 아직 초기화되지 않았습니다.");
  },
  _setFunctions(add, remove) {
    this.addToast = add;
    this.removeToast = remove;
  },
};

export default toast;

이 toast 객체는 React 바깥에서도 접근 가능한 전역 싱글턴이다. 초기에는 아무 기능도 없지만, 나중에 ToastProvider가 마운트되면서 내부 함수가 주입된다.

ToastProvider안에서 함수 주입과 this 바인딩


toast._setFunctions = function(add, remove) {
  this.addToast = add;     // toast.addToast에 등록
  this.removeToast = remove;
};

export const ToastProvider= ({...}:ToastProps) => {
  ...
	const addToast = (...) => {...}
	const removeToast =(...) => {...}
	
	useEffect(() => {
	  toast._setFunctions(addToast, removeToast);
	}, []);
	
	...
}

function App(){
  return (
    <ToastProvider maxToasts={10}>...<AppRouter /> ... </ToastProvider>

toast._setFunction는 this가 해당 객체(toast)를 가리킨다. 덕분에 외부에서도 toast.addToast()를 쓸 수 있게 된다.

this는 호출방식에 따라 바인딩되는 객체가 달라진다.

사용방식

// utils/handleError.ts

import toast from "@/utils/toast";

export function handleError(message: string) {
  toast.addToast({
    type: "delete",
    content: `에러 발생: ${message}`,
    options: { autoClose: true },
  });
}

정리

React 커스텀 훅은 범위(scope)에 제한이 있다는 단점이 있다. 그 한계를 벗아나기 위해서는 this 바인딩을 활용한 전역 유틸 패턴을 사용하는 것이 좋은 해결책이 될 수 있다.

이런 패턴은 toast뿐 아니라, 전역 알림, 로딩 처리, 다이얼로그 관리등에도 확장할 수 있다.