如何使此代码与 react-router v6 兼容

How to make this code compatible for react-router v6

在ProtectedRoute.js中我编码了:

const ProtectedRoute = ({ component: Component, ...rest }) => {
  const { loading, isAuthenticated, user } = useSelector((state) => state.user);
  return (
    <Fragment>
      {!loading && (
          <Routes>
        <Route
          {...rest}
          render={(props) => {
            if (!isAuthenticated) {
              return <Navigate to="/login" />;
            }
            return <Component {...props} />;
          }}
        />
        </Routes>
      )}
    </Fragment>
  );
};

export default ProtectedRoute;

在App.js中我写成:

function App() {
  const { isAuthenticated, user } = useSelector((state) => state.user);
  useEffect(() => {
    WebFont.load({
      google: { families: ["Roboto", "Droid Sans", "Chilanka"] },
    });
    store.dispatch(loadUser());
  }, []);

  return (
    <Router>
      <Header />
      {isAuthenticated && <UserOptions user={user} />}
      <Routes>
        <Route exact path="/" element={<Home />} />
        <Route exact path="/product/:id" element={<ProductDetails />} />
        <Route exact path="/products" element={<Products />} />
        <Route path="/products/:keyword" element={<Products />} />
        <Route exact path="/search" element={<Search />} />
        <Route exact path="/login" element={<Authenticate />} />
        <ProtectedRoute exact path="/account" element={<Profile />} />
      </Routes>
      <Footer />
    </Router>
  );
}

export default App;

错误提示:[ProtectedRoute] 不是路由组件。路由的所有子组件必须是路由或 .

是不是少了什么!谢谢

如何翻转逻辑并像这样检查 ProtectedRoute 中的所有内容?

const ProtectedRoute = () => {
  const { loading, isAuthenticated, user } = useSelector((state) => state.user);
  
  if (loading) { return null; }

  if (!isAuthenticated) {
    return <Navigate to="/login" />;
  }

  return <Profile user={user} andWhateverElse={true} />;
};

export default ProtectedRoute;

function App() {
  const { isAuthenticated, user } = useSelector((state) => state.user);
  useEffect(() => {
    WebFont.load({
      google: { families: ["Roboto", "Droid Sans", "Chilanka"] },
    });
    store.dispatch(loadUser());
  }, []);

  return (
    <Router>
      <Header />
      {isAuthenticated && <UserOptions user={user} />}
      <Routes>
        <Route exact path="/" element={<Home />} />
        <Route exact path="/product/:id" element={<ProductDetails />} />
        <Route exact path="/products" element={<Products />} />
        <Route path="/products/:keyword" element={<Products />} />
        <Route exact path="/search" element={<Search />} />
        <Route exact path="/login" element={<Authenticate />} />
        <Route exact path="/account" element={<ProtectedRoute />} />
      </Routes>
      <Footer />
    </Router>
  );
}

export default App;

react-router-dom 中不再使用自定义路由组件。 Routes 个组件只能有 RouteReact.Fragment 个组件作为子组件,Route 个组件只能有 Routes 个或其他 Route 个组件作为父组件.

相反,包装器组件处理业务逻辑,并为嵌套的 Route 组件呈现 children 属性或 Outlet,或为重定向呈现 Navigate

渲染children

const ProtectedRoute = ({ children }) => {
  const { loading, isAuthenticated, user } = useSelector((state) => state.user);

  if (loading) return null;

  return isAuthenticated
    ? children
    : <Navigate to="/login" replace />;
};

...

<Route
  path="/account"
  element={(
    <ProtectedRoute>
      <Profile />
    </ProtectedRoute>
  )}
/>

渲染Outlet

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

const ProtectedRoute = () => {
  const { loading, isAuthenticated, user } = useSelector((state) => state.user);

  if (loading) return null;

  return isAuthenticated
    ? <Outlet />
    : <Navigate to="/login" replace />;
};

...

<Route path="/account" element={<ProtectedRoute />}>
  <Route path="/account" element={<Profile />} />
</Route>

使用 Outlet 的好处是您可以使用单个身份验证包装器组件并在其中呈现任意数量的嵌套 Route 子级,而使用 children 方法则不能呈现嵌套路由,除非您将它们包装在 Routes 组件中。