繁体   English   中英

使用 i18n 反应路由器 V6 嵌套路由

[英]React Router V6 nested Routes with i18n

我有一个关于嵌套 i18n 的 React Router V6 的问题。

这是我的第一个多语言服务。

const MainPage:React.FC = () => {

  const lang = i18n.language;

  return (
    <>
      <Wrapper>
        <Routes>
          {/* Main */}
          <Route path={`/`} element={<Home />}>
            <Route path={`${lang}`}>
              <Route path={`service`}>
                <Route path={'slack'} element={<Slack />} />
              </Route>
            </Route>
            {/* <Route path={`service/dooray`}element={<Dooray />} /> */}
            {/* <Route path={`contact`} element={<Contact />} /> */}

            {/* <Route path={`app/sign-in`} element={<SignIn />} /> */}
            {/* <Route path={`app/sign-up`} element={<SignUp />} /> */}
            {/* <Route path={`app/mail-code`} element={<MailCode />} /> */}
            {/* <Route path={`app/password/reset`} element={<PwdReset />} /> */}

            {/* <Route path={`policies/privac`} element={<Privacy />} /> */}
            {/* <Route path={`policies/terms`} element={<Terms />} /> */}
          </Route>
          {/* <Route path={`*`} element={<>NOT FOUND</>} /> */}
          {/* test */}
        </Routes>
      </Wrapper>
      <ParentModal />
    </>

如果我输入 localhost:3000/en,则会出现错误'This means it will render an <Outlet /> with a null value by default resulting in an "empty" page.'

我该如何解决它..

我想要 /en => go 到英文页面,/jp => go 到日文页面


const MainPage:React.FC =() => {

...

<Route path={`/`} element={<Home />}>
    <Route path={`/${lang}/*`}>
       <Route path={`service`}>
           <Route path="slack" element={<Slack />} />
       </Route>
    </Route>
</Route>
}
const Home:React.FC = () => {

 return (
 <>
   ... UI, JSX
   <Outlet />
 </>
 )
}

我添加了一个<Outlet /> 但是如果我输入 '/ko/service/slack',现在渲染<Home />


<Route path={`/`} element={<Home />}>
    <Route path="service">
       <Route path="slack" element={<Slack />} />
       <Route path="dooray" element={<Dooray />} />
    </Route>
</Route>

嵌套路由不起作用.. :(

问题

错误'This means it will render an <Outlet /> with a null value by default resulting in an "empty" page.' 表示父路由没有为要渲染的嵌套路由渲染Outlet组件。 渲染Home组件的路由似乎没有渲染Outlet

解决方案

更新Home组件以呈现Outlet 请注意,没有element prop 的Route组件将默认呈现一个Outlet

例子:

import { Outlet } from 'react-router-dom';

const Home = () => {
  ...

  return (
    <>
      ... home page UI/JSX ...
      <Outlet />
    </>
  );
};

...

const MainPage:React.FC = () => {
  const lang = i18n.language;

  return (
    <>
      <Wrapper>
        <Routes>
          {/* Main */}
          <Route path="/" element={<Home />}>
            <Route path={lang}>   // <-- renders Outlet by default
              <Route path="service"> // <-- renders Outlet by default
                <Route path="slack" element={<Slack />} />
              </Route>
            </Route>
            ...
          </Route>
          ...
          {/* test */}
        </Routes>
      </Wrapper>
      <ParentModal />
    </>
  );
};

更新

如果HomeSlack组件是分开独立的,那么将Home组件移动到索引路由中,并简化到Slack组件的路由。

<Routes>
  <Route path="/">
    <Route index element={<Home />} />
    <Route path={`${lang}/service/slack`} element={<Slack />} />
  </Route>
</Routes>

编辑 react-router-v6-nested-routes-with-i18n

我有完全相同的用例(本地化反应路由器 v6)并想出了以下 LangRouter存储库链接

const LangRouter = () => {
  const { i18n } = useTranslation(),
    { pathname, search, hash } = useLocation(),
    navigate = useNavigate(),
    availableLocales = ['en', 'ar'],
    defaultLocale = (
      getDefaultLanguage() === 'en' || getDefaultLanguage() === 'ar' ? getDefaultLanguage() : 'en'
    ) as string,
    pathnameLocale = pathname.substring(1, 3).toLowerCase(),
    [locale, setLocale] = useState(defaultLocale),
    loaderTimerRef = useRef<any>(),
    [isLoading, setIsLoading] = useState(true);

  useEffect(() => {
    loaderTimerRef.current = setTimeout(() => {
      setIsLoading(false);
      clearTimeout(loaderTimerRef.current);
    }, 300);
  }, []);

  useEffect(() => {
    if (availableLocales.includes(pathnameLocale)) {
      updateLocale(pathnameLocale);
    } else if (pathname === '/') {
      updateLocale(defaultLocale);
    }
    // eslint-disable-next-line
  }, [pathname]);

  useEffect(() => {
    let lang = defaultLocale;

    if (availableLocales.includes(pathnameLocale)) {
      lang = pathnameLocale;
      setLanguageHandler(lang);
    } else if (pathname === '/') {
      setLanguageHandler(lang);
    }
    // eslint-disable-next-line
  }, [locale]);

  const setLanguageHandler = (lang: string) => {
    if (lang === 'en') {
      i18n.changeLanguage('en-US');
    } else {
      i18n.changeLanguage('ar-SA');
    }
  };

  const updateLocale = (newLocale: string) => {
    const newPath = `/${newLocale}` + pathname.substring(3);

    if (locale !== newLocale) {
      if (newPath === `/${newLocale}/` || newPath === `/${newLocale}` || pathname === '/') {
        navigate(getHomePageUrl(newLocale));
      } else {
        navigate(`${newPath}${hash}${search}`);
      }
      setLocale(newLocale);
    } else if (newPath === `/${newLocale}/` || newPath === `/${newLocale}` || pathname === '/') {
      if (isAuthenticated()) {
        navigate(getHomePageUrl(newLocale));
      } else {
        navigate(getLoginPageUrl(newLocale));
      }
    }
  };

  if (isLoading) {
    return (
      <div className="loader-wrapper">
        <LoadingIcon />
      </div>
    );
  }

  return (
    <LocaleContext.Provider value={{ locale, setLocale: updateLocale }}>
      <Routes>
        <Route path={`/${locale}`} element={<App />}>
          {publicRoutes.map((el, i) => (
            <Route
              key={i}
              path={el.path(locale)}
              element={
                <PublicRouteGuard
                  restricted={el.restricted}
                  redirect={el.redirect ? el.redirect(locale) : undefined}
                >
                  {el.element}
                </PublicRouteGuard>
              }
            />
          ))}

          {privateRoutes.map((el, i) => (
            <Route
              key={i}
              path={el.path(locale)}
              element={
                el.permissions ? (
                  <RestrictedRouteGuard requiredPermissions={el.permissions}>
                    {el.element}
                  </RestrictedRouteGuard>
                ) : (
                  <PrivateRouteGuard>{el.element}</PrivateRouteGuard>
                )
              }
            >
              {el.children &&
                el.children.map((innerEl, innerI) => (
                  <Route key={innerI} path={innerEl.path(locale)} element={innerEl.element} />
                ))}
            </Route>
          ))}
        </Route>
        <Route path="*" element={<NotFoundPage />} />
      </Routes>
    </LocaleContext.Provider>
  );
};

export default LangRouter;

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM