1

I'm trying to implement a redirect based on a property passed to a component nested deep within my route hierarchy. Right now I know 2 options how to do it.

const MyComponent = ({ variable }: { variable: string }) => {
  return variable === "xxx" ? <Navigate to={"/some/location"} replace> : null;
};

versus

const MyComponent = ({ variable }: { variable: string }) => {
  const navigate = useNavigate();
    
  useEffect(() => {
    if (variable === "xxx") {
      navigate("/some/location", { replace: true })
    }
  }, [navigate, variable]);

  return null;
};

Are these two approaches technically the same? The AI told me that using navigate inside an effect will cause a flash for the user, while returning Navigate would "immediately trigger navigate without any flash".

2
  • 1
    If you are using React Router in data mode or framework mode you can potentially use a third option: redirecting in a loader. This option is only available if you can derive the condition for redirecting flow the arguments in a loader. Loader redirect happens before render reactrouter.com/start/framework/route-module#loader Commented Nov 17 at 20:01
  • 1
    The advantage of redirecting in a loader is that you can take advantage of the lazy prop on Route, splitting the component and loader. That way you can redirect without having to wait for the component javascript to be downloaded reactrouter.com/start/data/route-object#lazy Commented Nov 17 at 20:31

1 Answer 1

1

Are these two approaches technically the same?

Yes. The two implementations are technically/functionally identical. The Navigate component uses the useNavigate and useEffect hooks and returns null under the hood.

Navigate

export function Navigate({
  to,
  replace,
  state,
  relative,
}: 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.`,
  );

  let { static: isStatic } = React.useContext(NavigationContext);

  warning(
    !isStatic,
    `<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 { matches } = React.useContext(RouteContext);
  let { pathname: locationPathname } = useLocation();
  let navigate = useNavigate();

  // Resolve the path outside of the effect so that when effects run twice in
  // StrictMode they navigate to the same place
  let path = resolveTo(
    to,
    getResolveToMatches(matches),
    locationPathname,
    relative === "path",
  );
  let jsonPath = JSON.stringify(path);

  React.useEffect(() => {
    navigate(JSON.parse(jsonPath), { replace, state, relative });
  }, [navigate, jsonPath, relative, replace, state]);

  return null;
}

Think of the Navigate component as "syntactic sugar" to replace using useNavigate and useEffect manually yourself.

The AI told me that using navigate inside an effect will cause a flash for the user, while returning Navigate would "immediately trigger navigate without any flash".

This is incorrect, they both should behave the same. The reason for the "flash of content" when using the useEffect hook and navigate function is because React runs all the enqueued effects at the end of the render cycle. This means whatever the MyComponent normally returns will be rendered at least once and then the effect will run and effect a navigation change.

Sign up to request clarification or add additional context in comments.

2 Comments

Thank you, Drew. "When you return and render the Navigation component the navigation will be immediately effected." This is the part my question is about. How is that done technically? Is the Navigation component wrapper around useLayoutEffect calling navigate from useNavigate? Or how is possible the flash is not there?
Here's the Navigate component source code. Are you sure there is no "content flash" when you use it? It effectively uses the useNavigate hook, issues the navigation action via useEffect hook call, and returns null, which is basically your second snippet. After looking at the source code now, I will amend my answer because I think they are actually technically/functionally the same.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.