簡體   English   中英

React Router Redirect 不渲染組件

[英]React Router Redirect does not render the component

這是我的 App.js:

function App() {
  return (
    <BrowserRouter>
      <AuthProvider>
        <Switch>
          <PrivateRoute path="/" component={MainPage} />
          <PrivateRoute path="/admin" component={MainPage} />
          <Container
            className="d-flex align-items-center justify-content-center"
            style={{ minHeight: "100vh" }}
          >
            <div className="w-100" style={{ maxWidth: "400px" }}>
              <Route path="/signup" component={Signup} />
              <Route path="/login" component={Login} /> //The component part
              <Route path="/forgot-password" component={ForgotPassword} />
            </div>
          </Container>
        </Switch>
      </AuthProvider>
    </BrowserRouter>
  );
}

來自 firebase 的 PriveRoute 組件的身份驗證上下文:

export default function PrivateRoute({ component: Component, ...rest }) {
  const { currentUser } = useAuth();

  return (
    <Route
      render={(props) => {
        return currentUser ? <Admin {...props} /> : <Redirect to="/login" />; // it redirects when the user does not log in.
      }}
    ></Route>
  );

登錄組件:

export default function Login() {
  const emailRef = useRef();
  const passwordRef = useRef();
  const { login, currentUser } = useAuth();
  const [error, setError] = useState("");
  const [loading, setLoading] = useState(false);
  const history = useHistory();

  if (currentUser) {
    history.push("/admin/mainpage");
  }
  async function handleSubmit(e) {
    e.preventDefault();

    try {
      setError("");
      setLoading(true);
      await login(
        emailRef.current.value + "@myosmail.com",
        passwordRef.current.value
      );
      history.push("/admin/mainpage");
    } catch {
      setError("Failed to log in");
    }

    setLoading(false);
  }

  return (
    <>
      <Card>
        <Card.Body>
          <h2 className="text-center mb-4">Log In</h2>
          {error && <Alert variant="danger">{error}</Alert>}
          <Form onSubmit={handleSubmit}>
            <Form.Group id="email">
              <Form.Label>Username</Form.Label>
              <Form.Control ref={emailRef} required />
            </Form.Group>
            <Form.Group id="password">
              <Form.Label>Password</Form.Label>
              <Form.Control type="password" ref={passwordRef} required />
            </Form.Group>
            <Button disabled={loading} className="w-100" type="submit">
              Log In
            </Button>
          </Form>
          <div className="w-100 text-center mt-3">
            <Link to="/forgot-password">Forgot Password?</Link>
          </div>
        </Card.Body>
      </Card>
      <div className="w-100 text-center mt-2">
        Need an account? <Link to="/signup">Sign Up</Link>
      </div>
    </>
  );
}

如果用戶沒有登錄,我想構建一個組件,它無法訪問我的 web 站點的內容,所以我構建了上面的組件。 但問題是,當我打開我的頁面並且沒有登錄時,頁面將我重定向到“/login”,但沒有呈現登錄組件,我不明白問題出在哪里。 我調試了我的組件,我看到我的代碼首先轉到 PrivateRoute 組件,然后它重定向到“/ login”,但是當頁面重定向到 Login 時沒有呈現任何內容。 當我從 App.js 中刪除 PrivateRoutes 時,我的代碼工作正常。

問題

我的猜測是您首先在Switch組件中放置了一個“/”路徑:

<PrivateRoute path="/" component={MainPage} />

重定向到“/login”有效,但Switch匹配“/”部分並嘗試再次呈現此私有路由。

您的私有路由也格式不正確,它不會傳遞收到的所有Route道具。

解決方案

修復私有路由組件以傳遞所有道具。

export default function PrivateRoute({ component: Component, ...rest }) {
  const { currentUser } = useAuth();

  return (
    <Route
      {...rest}
      render={(props) => {
        return currentUser ? <Admin {...props} /> : <Redirect to="/login" />;
      }}
    />
  );
}

Switch組件路徑順序和特異性問題中,您希望在不太具體的路徑之前排序更具體的路徑。 “/”是所有路徑的路徑前綴,因此您希望在其他路徑之后使用它。 嵌套路由也需要在Switch中呈現,因此只返回和呈現一個匹配項。

<BrowserRouter>
  <AuthProvider>
    <Switch>
      <Container
        className="d-flex align-items-center justify-content-center"
        style={{ minHeight: "100vh" }}
      >
        <div className="w-100" style={{ maxWidth: "400px" }}>
          <Switch>
            <Route path="/signup" component={Signup} />
            <Route path="/login" component={Login} /> //The component part
            <Route path="/forgot-password" component={ForgotPassword} />
          </Switch>
        </div>
      </Container>
      <PrivateRoute path={["/admin", "/"]} component={MainPage} />
    </Switch>
  </AuthProvider>
</BrowserRouter>

更新

不過,我對您的私有路由感到有些困惑,您在component道具上指定了MainPage組件,然后在其中渲染了一個Admin組件。 通常,一個更不可知的PrivateRoute組件可能看起來更像:

const PrivateRoute = props => {
  const { currentUser } = useAuth();

  return currentUser ? <Route {...props} /> : <Redirect to="/login" />;
}

這允許您使用所有正常的Route組件道具,並且不限於使用component道具。

用途:

  •  <PrivateRoute path="/admin" component={Admin} />
  •  <PrivateRoute path="/admin" render={props => <Admin {...props} />} />
  •  <PrivateRoute path="/admin"> <Admin /> </PrivateRoute>

我也遇到過同樣的問題。 這解決了我。 用 Switch 包裹您的三個路線。

<Switch>
    <Route path="/signup" component={Signup} />
    <Route path="/login" component={Login} />
    <Route path="/forgot-password" component={ForgotPassword} />
</Switch>

由於第一個私有路由有根路徑,它總是 go 到路由。 您可以將精確用於第一條私有路由。 但最好的方法應該是放置第一條私人路線

<PrivateRoute path={["/admin", "/"]} component={MainPage} />

在底部。 因此,當沒有匹配時,它只會去那里。

您沒有將路徑傳遞到ProtectedRoute中的Route

<Route
      {...rest} // spread the test here
      render={(props) => {
        return currentUser ? <Admin {...props} /> : <Redirect to="/login" />; // it redirects when the user does not log in.
      }}
    ></Route>

還像@Drew Reese 提到的那樣切換路徑的路線。

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM