Я пытаюсь реализовать частный маршрут к моему приложению, и хотя он правильно достигает частного маршрута при аутентификации, он перенаправляет его на страницу входа, а не на дочерние элементы. Я пробовал каждое решение в stackoverflow, но они, похоже, не работают. Это странно, потому что он достигает правильного пути (я печатаю на консоль всякий раз, когда достигаю частного маршрута), но не может правильно перенаправить страницу.
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();
// add loading state, initially true for initial render
const [isLoading, setIsLoading] = useState(true);
const checkAuth = async () => {
const cookie = new Cookies();
setIsLoading(true); // <-- set true when starting auth check
try {
if (cookie.get("stytch_session") == null) {
console.info("no cookies!")
setIsAuthenticated(false);
} else {
Axios.post(
"http://localhost:5001/test",
{},
{ headers: { sessiontoken: cookie.get("stytch_session") } }
)
.then((response) => {
console.info("reaching private route!")
setIsAuthenticated(true);
})
.catch((err) => {
console.info(err)
setIsAuthenticated(false);
});
}
} finally {
setIsLoading(false); // <-- clear loading state when completed
}
};
useEffect(() => {
checkAuth();
}, []);
if (isLoading) {
return <div className = "">Loading...</div>;
}
return isAuthenticated ? children : <Navigate to = {"/login"} />;
}
А вот фрагмент кода, который вызывается в app.js
<Route
path = "/scroll"
element = {(
<ProtectedRoute>
<Scroll />
</ProtectedRoute>
}
/>
Я не думаю, что это действительно решает мою проблему, потому что, хотя кажется, что оно игнорирует истинное/ложное значение isAuthenticated и переходит на страницу входа независимо...
@jasonmzx Выполнение подобных перенаправлений приведет к перезагрузке всей страницы, другими словами, все приложение будет перемонтировано. Большинству людей это не нравится, потому что это ненужно и этого можно избежать.



![Безумие обратных вызовов в javascript [JS]](https://i.imgur.com/WsjO6zJb.png)


Не могли бы вы попробовать использовать Outlet, если ваш частный маршрут является дочерним элементом компонента ProtectedRoute? Вроде след.
return isAuthenticated ? <Outlet />: <Navigate to = {"/login"} />;
Только что попробовал, ничего не меняется, к сожалению...
@kruskal123 Ты так оборачиваешь свой частный маршрут <Route path='/protected-route-path' element = {<ProtectedRoute/>}><Route path='/private-route-path' element = {<PrivateRoute/>}><.Route>? Поскольку я разработал приложение того же типа, что и ваше, и оно отлично работало.
Извините, не могли бы вы дважды проверить синтаксис, я не уверен, правильно ли закрыты маршруты в вашем коде. Вот маршрут, который я указал в своем коде: <Route path = "/scroll" element = { <ProtectedRoute> <Scroll /> </ProtectedRoute> } /> (где прокрутка — это защищенный путь)
...</Route> правильно, извините за это. Но я понял вашу структуру. ProtectedRoute должен выполнить повторную визуализацию, вызвав setIsAuthenticated(true). Он действительно доходит туда?
Попробуйте удалить finally и вставить
useEffect(()=>{
if (isAuthenticated !== null){
setIsLoading(false);
}
},[isAuthenticated])
Мне кажется, что ваши обновления состояния собираются или разрешаются в неправильном порядке. Это гарантирует, что isLoading останется истинным до тех пор, пока isAuthenticated не получит реальное значение.
FWIW, пакетные или нет, обновления состояния React всегда обрабатываются в том порядке, в котором они поставлены в очередь. Это не async, поэтому нечего «решать».
Я не могу добавить эту функцию, так как она дает мне «React Hook», «useEffect» вызывается в функции «checkAuth», которая не является ни компонентом функции React, ни пользовательской функцией React Hook. Имена компонентов React должны начинаться с верхнего регистра буква. Имена React Hook должны начинаться со слова «использовать» ошибку react-hooks/rules-of-hooks
@ kruskal123 вы поместили его в то же место, а не с другим эффектом использования? Идет с другим. В конечном итоге это будет иметь тот же эффект, что и ожидание, но вместо ожидания оно использует обновление в качестве триггера.
axios.post запускает асинхронную цепочку Promise, которую синхронный код вокруг него не ждет. Блок finally выполняется до разрешения POST-запроса.
Код должен await Обещание решить.
export default function ProtectedRoute() {
const [isAuthenticated, setIsAuthenticated] = useState();
// add loading state, initially true for initial render
const [isLoading, setIsLoading] = useState(true);
const checkAuth = async () => {
const cookie = new Cookies();
setIsLoading(true);
try {
if (cookie.get("stytch_session") == null) {
console.info("no cookies!")
setIsAuthenticated(false);
} else {
await Axios.post(
"http://localhost:5001/test",
{},
{ headers: { sessiontoken: cookie.get("stytch_session") } }
);
console.info("reaching private route!")
setIsAuthenticated(true);
} catch(err) {
console.info(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 />} />
... other protected routes ...
</Route>
Пытался добавить дополнительную часть ожидания ответа const, но я не могу сделать это, не получив ошибку компилятора «Отсутствует инициализатор в объявлении const». Есть ли другой способ дождаться вызова axios?
На самом деле извините, неважно, забыл добавить «=» между ответом и ожиданием. Теперь работает отлично, спасибо!!
@ kruskal123 Ах, извините, опечатка с моей стороны. На самом деле, поскольку не похоже, что код пользовательского интерфейса нуждается в response для чего-либо, вы могли бы также просто await Axios.post(....).
Мне нравится делать перенаправления в React с помощью встроенной переменной
window, для простого перенаправления URL просто сделайтеwindow.location.href = "/private";, и он будет перенаправляться очень хорошо.