react-router에는 hook과 동일한 동작을 하는 component들이 존재한다. 예를들어 useNavigate라는 훅이 있으면 Navigate라는 컴포넌트도 정의되어 있는 것이다.
Navigate코드보기
코드를 살펴보면 상당히 간단하게 되어 있는 것을 알 수 있다. invariant와 waring은 에러를 처리하는 부분이니 넘어가면 useNavigate 훅을 받아서 useEffect에서 해당 훅을 실행하는 것을 확인할 수 있다.
아래 useNavigate코드를 보면 알 수 있듯이 NavigateFunction 타입이 To와 NavigationOptions를 받는것을 알 수 있다. 여기서 NavigationOptions가 replace와 state를 옵셔널로 가지는 타입이기 때문에 Navigate컴포넌트에서 replace와 state를 prop으로 받아주는 것을 볼 수 있다.
export function Navigate({ to, replace, state }: NavigateProps): null {
invariant(
useInRouterContext(),
// TODO: This error is probably because they somehow have 2 versions of
// the router loaded. We can help them understand how to avoid that.
`<Navigate> may be used only in the context of a <Router> component.`
);
warning(
!React.useContext(NavigationContext).static,
`<Navigate> must not be used on the initial render in a <StaticRouter>. ` +
`This is a no-op, but you should modify your code so the <Navigate> is ` +
`only ever rendered in response to some user interaction or state change.`
);
let navigate = useNavigate();
React.useEffect(() => {
navigate(to, { replace, state });
});
return null;
}
TypeScript
복사
useNavigate 코드보기
export interface NavigateFunction {
(to: To, options?: NavigateOptions): void;
(delta: number): void;
}
export interface NavigateOptions {
replace?: boolean;
state?: any;
}
export function useNavigate(): NavigateFunction {
invariant(
useInRouterContext(),
// TODO: This error is probably because they somehow have 2 versions of the
// router loaded. We can help them understand how to avoid that.
`useNavigate() may be used only in the context of a <Router> component.`
);
let { basename, navigator } = React.useContext(NavigationContext);
let { matches } = React.useContext(RouteContext);
let { pathname: locationPathname } = useLocation();
let routePathnamesJson = JSON.stringify(
matches.map((match) => match.pathnameBase)
);
let activeRef = React.useRef(false);
React.useEffect(() => {
activeRef.current = true;
});
let navigate: NavigateFunction = React.useCallback(
(to: To | number, options: NavigateOptions = {}) => {
warning(
activeRef.current,
`You should call navigate() in a React.useEffect(), not when ` +
`your component is first rendered.`
);
if (!activeRef.current) return;
if (typeof to === "number") {
navigator.go(to);
return;
}
let path = resolveTo(
to,
JSON.parse(routePathnamesJson),
locationPathname
);
if (basename !== "/") {
path.pathname = joinPaths([basename, path.pathname]);
}
(!!options.replace ? navigator.replace : navigator.push)(
path,
options.state
);
},
[basename, navigator, routePathnamesJson, locationPathname]
);
return navigate;
}
TypeScript
복사
이처럼 wrapper component도 결국 hook으로 구현되어 있기 때문에 함수형 컴포넌트 내에서 사용하려면 그냥 hook을 사용하면 될 것 같다. 각각의 상황에 맞게 사용해보자!