yamoo9 / likelion-FEQA

질문/답변 — 프론트엔드 스쿨, 멋사
29 stars 9 forks source link

[LAB-16] useLayoutEffect에서 토큰 검사 후 다른 페이지로 이동 시 useEffect도 수행됨 #291

Closed no-support closed 1 year ago

no-support commented 1 year ago

질문 작성자

노지원

문제 상황

yamoo9 commented 1 year ago

문제 상황

useNavigate 훅의 navigate 함수를 useLayoutEffect 훅 내부에서 사용하니 useEffect 훅을 사용 하라고 경고합니다.

문제 발생 원인 분석

React Router의 useNavigate 훅 코드를 살펴보면 경고가 발생한 이유를 유추할 수 있습니다.

아래 그림에 표시된 부분에서 확인할 수 있듯이 useNavigate 훅이 반환하는 navigate 함수는 activeRef.current 값이 true가 아닌 경우 warning 함수에 의해 경고가 출력됩니다. 그리고 activeRef.current 값은 useEffect 훅에 의해 값이 true로 변경됩니다.

그러므로 useEffect 훅보다 먼저 실행되는 useLayoutEffect 훅의 이펙트 함수가 작동될 때는 아직 activeRef.current 값이 false이므로 navigate 함수가 실행될 때 경고가 출력되는 것입니다.

아래 코드는 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;
}
no-support commented 1 year ago

activeRef.current값이 false이면 navigate 함수를 return으로 종료시켜버리는군요..!😮 감사합니다!!!🤩