React Router Dom私有路由不起作用

huangapple go评论72阅读模式
英文:

React Router Dom Private Route not Working

问题

这是您提供的代码的翻译部分:

PrivateRoute:

import { useState, useEffect } from 'react';
import { useRef } from 'react';
import { Outlet, Navigate, useLocation } from 'react-router-dom';
import Axios from "axios";
import Cookies from "universal-cookie";

export default function ProtectedRoute({ children }) {
  const [isAuthenticated, setIsAuthenticated] = useState();
  // 添加加载状态,最初为true以进行初始渲染
  const [isLoading, setIsLoading] = useState(true);
  const checkAuth = async () => {
    const cookie = new Cookies(); 
    setIsLoading(true); // <-- 在开始进行身份验证检查时设置为true
    try {
      if (cookie.get("stytch_session") == null) {
        console.log("没有Cookie!")
        setIsAuthenticated(false);
      } else {
        Axios.post(
          "http://localhost:5001/test",
          {},
          { headers: { sessiontoken: cookie.get("stytch_session") } }
        )
          .then((response) => {
            console.log("到达私有路由!")
            setIsAuthenticated(true);
          })
          .catch((err) => {
            console.log(err)
            setIsAuthenticated(false);
          });
      }
    } finally {
      setIsLoading(false); // <-- 当完成时清除加载状态
    }
  };

  useEffect(() => {
    checkAuth();
  }, []);

  if (isLoading) {
    return <div className=""></div>;
  }

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

}

这是在app.js中调用的代码片段:

<Route
  path="/scroll"
  element={(
    <ProtectedRoute>
      <Scroll /> 
    </ProtectedRoute>
  }
/> 

希望这些翻译对您有所帮助。如果您有任何其他问题,请随时提出。

英文:

I am trying to implement a private route towards my application, and while it correctly reaches the private route when authenticated, it redirects it to the login page rather than the children. I've tried every solution on stackoverflow but they don't seem to work. It's strange because it reaches the right path (I print to console whenever I reach the private route) but it's not able to redirect the page correctly.

PrivateRoute

import { useState, useEffect } from &#39;react&#39;;
import { useRef } from &#39;react&#39;;
import { Outlet, Navigate, useLocation } from &#39;react-router-dom&#39;;
import Axios from &quot;axios&quot;;
import Cookies from &quot;universal-cookie&quot;;

export default function ProtectedRoute({ children }) {
  const [isAuthenticated, setIsAuthenticated] = useState();
  // add loading state, initially true for initial render
  const [isLoading, setIsLoading] = useState(true);
  const checkAuth = async () =&gt; {
    const cookie = new Cookies(); 
    setIsLoading(true); // &lt;-- set true when starting auth check
    try {
      if (cookie.get(&quot;stytch_session&quot;) == null) {
        console.log(&quot;no cookies!&quot;)
        setIsAuthenticated(false);
      } else {
        Axios.post(
          &quot;http://localhost:5001/test&quot;,
          {},
          { headers: { sessiontoken: cookie.get(&quot;stytch_session&quot;) } }
        )
          .then((response) =&gt; {
            console.log(&quot;reaching private route!&quot;)
            setIsAuthenticated(true);
          })
          .catch((err) =&gt; {
            console.log(err)
            setIsAuthenticated(false);
          });
      }
    } finally {
      setIsLoading(false); // &lt;-- clear loading state when completed
    }
  };

  useEffect(() =&gt; {
    checkAuth();
  }, []);

  if (isLoading) {
    return &lt;div className=&quot;&quot;&gt;Loading...&lt;/div&gt;;
  }

  return isAuthenticated ? children : &lt;Navigate to={&quot;/login&quot;} /&gt;;

}

And here is the code snippet that's called in app.js

&lt;Route
  path=&quot;/scroll&quot;
  element={(
    &lt;ProtectedRoute&gt;
      &lt;Scroll /&gt; 
    &lt;/ProtectedRoute&gt;
  }
/&gt; 

答案1

得分: 1

The axios.post 启动了一个异步 Promise 链,同步代码不会等待它。finally 块在 POST 请求解析之前执行。

代码应该 await 该 Promise 来解析。

export default function ProtectedRoute() {
  const [isAuthenticated, setIsAuthenticated] = useState();

  // 添加加载状态,初始值为 true,用于初始渲染
  const [isLoading, setIsLoading] = useState(true);

  const checkAuth = async () => {
    const cookie = new Cookies(); 
    setIsLoading(true);

    try {
      if (cookie.get("stytch_session") == null) {
        console.log("no cookies!")
        setIsAuthenticated(false);
      } else {
        await Axios.post(
          "http://localhost:5001/test",
          {},
          { headers: { sessiontoken: cookie.get("stytch_session") } }
        );
        console.log("reaching private route!")
        setIsAuthenticated(true);
    } catch(err) {
      console.log(err);
      setIsAuthenticated(false);
    } finally {
      setIsLoading(false);
    }
  };

  useEffect(() => {
    checkAuth();
  }, []);

  if (isLoading) {
    return <div className="">Loading...</div>;
  }

  return isAuthenticated ? <Outlet /> : <Navigate to="/login" replace />;
}
<Route element={<ProtectedRoute />}>
  <Route path="/scroll" element={<Scroll />} />
  ...其他受保护的路由...
</Route>
英文:

The axios.post starts an asynchronous Promise chain that the synchronous code around it doesn't wait for. The finally block is executed prior to the POST request resolving.

The code should await the Promise to resolve.

export default function ProtectedRoute() {
  const [isAuthenticated, setIsAuthenticated] = useState();

  // add loading state, initially true for initial render
  const [isLoading, setIsLoading] = useState(true);

  const checkAuth = async () =&gt; {
    const cookie = new Cookies(); 
    setIsLoading(true);

    try {
      if (cookie.get(&quot;stytch_session&quot;) == null) {
        console.log(&quot;no cookies!&quot;)
        setIsAuthenticated(false);
      } else {
        await Axios.post(
          &quot;http://localhost:5001/test&quot;,
          {},
          { headers: { sessiontoken: cookie.get(&quot;stytch_session&quot;) } }
        );
        console.log(&quot;reaching private route!&quot;)
        setIsAuthenticated(true);
    } catch(err) {
      console.log(err);
      setIsAuthenticated(false);
    } finally {
      setIsLoading(false);
    }
  };

  useEffect(() =&gt; {
    checkAuth();
  }, []);

  if (isLoading) {
    return &lt;div className=&quot;&quot;&gt;Loading...&lt;/div&gt;;
  }

  return isAuthenticated ? &lt;Outlet /&gt; : &lt;Navigate to=&quot;/login&quot; replace /&gt;;
}
&lt;Route element={&lt;ProtectedRoute /&gt;}&gt;
  &lt;Route path=&quot;/scroll&quot; element={&lt;Scroll /&gt;} /&gt;
  ... other protected routes ...
&lt;/Route&gt;

答案2

得分: 0

你可以尝试在你的私有路由是 ProtectedRoute 组件的子组件时使用 Outlet,就像下面这样。

return isAuthenticated ? <Outlet /> : <Navigate to={"/login"} />;
英文:

Could you try using Outlet if your private route is child of ProtectedRoute component? Like following.

return isAuthenticated ? &lt;Outlet /&gt;: &lt;Navigate to={&quot;/login&quot;} /&gt;;

答案3

得分: 0

尝试移除finally并替换为

useEffect(() => {
   if (isAuthenticated !== null) {
       setIsLoading(false);
   }
}, [isAuthenticated])

在我看来,你的状态更新可能正在批处理或以错误的顺序解析。这将确保 isLoading 保持为 true,直到 isAuthenticated 具有实际值。

英文:

Try removing the finally and putting in

useEffect(()=&gt;{
if(isAuthenticated !== null){
setIsLoading(false);
}
},[isAuthenticated])

What it looks like to me is that your state updates are being batched or resolving in the wrong order. This will ensure that isLoading remains true until isAuthenticated has a real value.

huangapple
  • 本文由 发表于 2023年3月31日 22:17:55
  • 转载请务必保留本文链接:https://go.coder-hub.com/75899594.html
匿名

发表评论

匿名网友

:?: :razz: :sad: :evil: :!: :smile: :oops: :grin: :eek: :shock: :???: :cool: :lol: :mad: :twisted: :roll: :wink: :idea: :arrow: :neutral: :cry: :mrgreen:

确定