React js 用户在刷新时被重定向到另一个页面
react js user gets redirected to another page on refresh
我有一个带有 react-router-dom v6 的 React js 应用程序来处理路由。在我添加 firebase firestore 之前,路由功能工作得很好,但现在由于某种原因,当我在搜索引擎页面中并重新加载它时,主页被渲染了。这不是用户身份验证的问题,因为这是由登录组件处理的,但我在我的配置中找不到问题。
这是我的应用组件。
import React, {useEffect, useState} from "react";
import { BrowserRouter, Routes, Route, Navigate } from "react-router-dom";
import { createBrowserHistory } from 'history';
import ReactDOM from "react-dom";
import "./styles/style.scss";
import Home from "./pages/home";
import Seeker from "./pages/seeker";
import NotFound from "./pages/notFound";
import Login from "./pages/login";
const App = () => {
const [token, setToken] = useState(false);
useEffect(() => {
if(localStorage.getItem("token") === null){
setToken(false);
} else {
setToken(true);
}
}, [])
return (
<BrowserRouter history={createBrowserHistory}>
<Routes>
<Route exact path="/" element={<Login isAuth={token}/>}/>
<Route exact path="/home" element={token ? <Home /> : <Navigate to="/"/>}/>
<Route exact path="/seeker" element={token ? <Seeker /> : <Navigate to="/"/>}/>
<Route path="*" element={<NotFound />}/>
</Routes>
</BrowserRouter>
)
}
ReactDOM.render(
<App />,
document.getElementById("root"))
登录组件在 localstorage 上正确设置令牌,路由使用它有条件地呈现组件。但是当我在“/seeker”url 中时,刷新将我带到“/home”。
import React, { useState, useEffect } from "react";
import { Formik, Form, Field, ErrorMessage } from 'formik';
import axios from "axios";
require("babel-core/register");
require("babel-polyfill");
import GridRender from "../components/gridRender";
import { NavBar } from "../components/navBar";
async function getHeros(name) {
return await axios.get(
`https://www.superheroapi.com/api.php/${name}`
);
}
const Seeker = () => {
const [searchedHero, setSearchedHero] = useState("")
const [matchedHeros, setMatchedHeros] = useState([]);
useEffect(() => {
let isMounted = true;
if (isMounted) {
getHeros(searchedHero).then((heros) => {
const hero = heros.data.response != "error" ? heros.data.results : []
localStorage.setItem("addHeroAction", "true");
setMatchedHeros(hero);
}, console.error);
}
return () => { isMounted = false };
}, [searchedHero]);
return (
<div>
<NavBar />
<div className="seeker">
<h1 className="title">Find your next teammate!</h1>
<Formik /> //// here is a large form that i erased so it doesn't get long
{matchedHeros.length != 0 && <GridRender matchedHeros = {matchedHeros}/>}
</div>
</div>
)
}
export default Seeker;
这里是我的 firebase 配置(我使用版本 9)以防它很重要,因为这个错误是在 firebase 实施后出现的。
import { initializeApp } from "firebase/app";
import "regenerator-runtime/runtime";
import { addDoc, deleteDoc, doc } from 'firebase/firestore';
import { getFirestore, collection } from 'firebase/firestore'
const firebaseConfig = {
apiKey: "xxxxxxxxxxxxxxxxxx",
authDomain: "xxxxxxxxxxxxxxxxxxxx",
databaseURL: "xxxxxxxxxxxxxxxxxxxxx",
projectId: "superteam-maker",
storageBucket: "xxxxxxxxxxxxxxx",
messagingSenderId: "xxxxxxxxxxxxx",
appId: "xxxxxxxxxxxxxxxxxxxxxxxxxx"
};
initializeApp(firebaseConfig);
const db = getFirestore();
const colRef = collection(db, "team")
const addHero = (hero) => {
addDoc(colRef, {
name : hero.name,
powerstats :{
combat: parseInt(hero.powerstats.combat),
durability: parseInt(hero.powerstats.durability),
intelligence: parseInt(hero.powerstats.intelligence),
power: parseInt(hero.powerstats.power),
speed: parseInt(hero.powerstats.speed),
strength : parseInt(hero.powerstats.strength)
},
id: parseInt(hero.id),
image: {url : hero.image.url},
} )
}
const deleteHero = (hero) => {
const docRef = doc(db, "team", hero.id);
deleteDoc(docRef);
}
export {addHero, deleteHero, colRef}
////////更新/////////
登录组件通过 API 测试 returns 一个 运行dom 令牌来验证用户,因此用户只能输入特定的电子邮件和密码提交。如果身份验证成功,用户将呈现到“/home”。
这是登录组件的代码。
import React, {useEffect, useState} from "react";
import { Formik } from 'formik';
import { Navigate } from 'react-router-dom';
import axios from "axios";
const Login = (props) => {
const [token, setToken] = useState(false);
useEffect(() => {
if(localStorage.getItem("token") === null){
setToken(false);
} else {
setToken(true);
}
}, [])
const verification = () => {
if( token && props.isAuth){
return <Navigate to="/home"/>
}
}
let logInError = {};
return(
<div className="login__background">
<div className="login container">
{verification()}
<h1 className="display-1 title login__title">Make a team as <span>powerfull</span> as you!</h1>
<h5 className="login-title__sub">Please log in to create your superteam</h5>
<Formik
initialValues={{ email: '', password: '' }}
validate={values => {
const errors = {};
if (!values.email) {
errors.email = 'Required';
} else if (
!/^[A-Z0-9._%+-]+@[A-Z0-9.-]+\.[A-Z]{2,}$/i.test(values.email)
) {
errors.email = 'Invalid email address';
}
if (!values.password){
errors.password = "Required";
}
return errors;
}}
onSubmit={(values) => {
axios.post("http://challenge-react.alkemy.org/", values)
.then(response => {
let token = response.data.token
localStorage.setItem("token", token);
localStorage.setItem("addHeroAction", false);
setToken(true);
return <Navigate to="/home"/>
})
.catch(error => {
if (error.response) {
logInError = error.response.data.error;
window.alert(logInError);
} else if (error.request) {
console.log(error.request);
} else {
console.log('Error', error.message);
}
console.log(error.config);
})
}}>
{({
values,
errors,
touched,
handleChange,
handleBlur,
handleSubmit
}) => (
<form onSubmit={handleSubmit}>
<label className="form-label label" name="email">Email</label>
<br />
<input
className="form-control form-control-lg input"
type="email"
name="email"
onChange={handleChange}
onBlur={handleBlur}
value={values.email}
/>
{errors.email && touched.email && errors.email}
<br />
<label className="form-label label " name="password">Password</label>
<br />
<input
className="form-control form-control-lg input"
type="password"
name="password"
onChange={handleChange}
onBlur={handleBlur}
value={values.password}
/>
{errors.password && touched.password && errors.password}
<br />
<button type="submit" className="btn btn-danger">
Submit
</button>
</form>
)}
</Formik>
</div>
</div>
)
}
export default Login;
它还会从 App.js 获取 IsAuth propr,以防用户第一次进入页面并且没有保存令牌。
我看到的问题是 token
状态最初是错误的。 useEffect
在渲染周期结束时运行,因此对于初始渲染 token
是 false
const [token, setToken] = useState(false);
useEffect(() => {
if (localStorage.getItem("token") === null) {
setToken(false);
} else {
setToken(true);
}
}, []);
并且使用 token
状态呈现的任何 Route
将使用此初始 false
值并相应地执行操作。
<Route path="/seeker" element={token ? <Seeker /> : <Navigate to="/" />} />
如果在 "/seeker"
路径上并且 token
值为 false
,则呈现 Navigate
组件。
假设您的所有身份验证流程都正确且有效并将 token
值设置到 localStorage,那么您应该从 [=35] 初始化 token
状态 =] localStorage.
const initializeState = () => !!JSON.parse(localStorage.getItem("token"));
const [token, setToken] = useState(initializeState);
我有一个带有 react-router-dom v6 的 React js 应用程序来处理路由。在我添加 firebase firestore 之前,路由功能工作得很好,但现在由于某种原因,当我在搜索引擎页面中并重新加载它时,主页被渲染了。这不是用户身份验证的问题,因为这是由登录组件处理的,但我在我的配置中找不到问题。
这是我的应用组件。
import React, {useEffect, useState} from "react";
import { BrowserRouter, Routes, Route, Navigate } from "react-router-dom";
import { createBrowserHistory } from 'history';
import ReactDOM from "react-dom";
import "./styles/style.scss";
import Home from "./pages/home";
import Seeker from "./pages/seeker";
import NotFound from "./pages/notFound";
import Login from "./pages/login";
const App = () => {
const [token, setToken] = useState(false);
useEffect(() => {
if(localStorage.getItem("token") === null){
setToken(false);
} else {
setToken(true);
}
}, [])
return (
<BrowserRouter history={createBrowserHistory}>
<Routes>
<Route exact path="/" element={<Login isAuth={token}/>}/>
<Route exact path="/home" element={token ? <Home /> : <Navigate to="/"/>}/>
<Route exact path="/seeker" element={token ? <Seeker /> : <Navigate to="/"/>}/>
<Route path="*" element={<NotFound />}/>
</Routes>
</BrowserRouter>
)
}
ReactDOM.render(
<App />,
document.getElementById("root"))
登录组件在 localstorage 上正确设置令牌,路由使用它有条件地呈现组件。但是当我在“/seeker”url 中时,刷新将我带到“/home”。
import React, { useState, useEffect } from "react";
import { Formik, Form, Field, ErrorMessage } from 'formik';
import axios from "axios";
require("babel-core/register");
require("babel-polyfill");
import GridRender from "../components/gridRender";
import { NavBar } from "../components/navBar";
async function getHeros(name) {
return await axios.get(
`https://www.superheroapi.com/api.php/${name}`
);
}
const Seeker = () => {
const [searchedHero, setSearchedHero] = useState("")
const [matchedHeros, setMatchedHeros] = useState([]);
useEffect(() => {
let isMounted = true;
if (isMounted) {
getHeros(searchedHero).then((heros) => {
const hero = heros.data.response != "error" ? heros.data.results : []
localStorage.setItem("addHeroAction", "true");
setMatchedHeros(hero);
}, console.error);
}
return () => { isMounted = false };
}, [searchedHero]);
return (
<div>
<NavBar />
<div className="seeker">
<h1 className="title">Find your next teammate!</h1>
<Formik /> //// here is a large form that i erased so it doesn't get long
{matchedHeros.length != 0 && <GridRender matchedHeros = {matchedHeros}/>}
</div>
</div>
)
}
export default Seeker;
这里是我的 firebase 配置(我使用版本 9)以防它很重要,因为这个错误是在 firebase 实施后出现的。
import { initializeApp } from "firebase/app";
import "regenerator-runtime/runtime";
import { addDoc, deleteDoc, doc } from 'firebase/firestore';
import { getFirestore, collection } from 'firebase/firestore'
const firebaseConfig = {
apiKey: "xxxxxxxxxxxxxxxxxx",
authDomain: "xxxxxxxxxxxxxxxxxxxx",
databaseURL: "xxxxxxxxxxxxxxxxxxxxx",
projectId: "superteam-maker",
storageBucket: "xxxxxxxxxxxxxxx",
messagingSenderId: "xxxxxxxxxxxxx",
appId: "xxxxxxxxxxxxxxxxxxxxxxxxxx"
};
initializeApp(firebaseConfig);
const db = getFirestore();
const colRef = collection(db, "team")
const addHero = (hero) => {
addDoc(colRef, {
name : hero.name,
powerstats :{
combat: parseInt(hero.powerstats.combat),
durability: parseInt(hero.powerstats.durability),
intelligence: parseInt(hero.powerstats.intelligence),
power: parseInt(hero.powerstats.power),
speed: parseInt(hero.powerstats.speed),
strength : parseInt(hero.powerstats.strength)
},
id: parseInt(hero.id),
image: {url : hero.image.url},
} )
}
const deleteHero = (hero) => {
const docRef = doc(db, "team", hero.id);
deleteDoc(docRef);
}
export {addHero, deleteHero, colRef}
////////更新/////////
登录组件通过 API 测试 returns 一个 运行dom 令牌来验证用户,因此用户只能输入特定的电子邮件和密码提交。如果身份验证成功,用户将呈现到“/home”。
这是登录组件的代码。
import React, {useEffect, useState} from "react";
import { Formik } from 'formik';
import { Navigate } from 'react-router-dom';
import axios from "axios";
const Login = (props) => {
const [token, setToken] = useState(false);
useEffect(() => {
if(localStorage.getItem("token") === null){
setToken(false);
} else {
setToken(true);
}
}, [])
const verification = () => {
if( token && props.isAuth){
return <Navigate to="/home"/>
}
}
let logInError = {};
return(
<div className="login__background">
<div className="login container">
{verification()}
<h1 className="display-1 title login__title">Make a team as <span>powerfull</span> as you!</h1>
<h5 className="login-title__sub">Please log in to create your superteam</h5>
<Formik
initialValues={{ email: '', password: '' }}
validate={values => {
const errors = {};
if (!values.email) {
errors.email = 'Required';
} else if (
!/^[A-Z0-9._%+-]+@[A-Z0-9.-]+\.[A-Z]{2,}$/i.test(values.email)
) {
errors.email = 'Invalid email address';
}
if (!values.password){
errors.password = "Required";
}
return errors;
}}
onSubmit={(values) => {
axios.post("http://challenge-react.alkemy.org/", values)
.then(response => {
let token = response.data.token
localStorage.setItem("token", token);
localStorage.setItem("addHeroAction", false);
setToken(true);
return <Navigate to="/home"/>
})
.catch(error => {
if (error.response) {
logInError = error.response.data.error;
window.alert(logInError);
} else if (error.request) {
console.log(error.request);
} else {
console.log('Error', error.message);
}
console.log(error.config);
})
}}>
{({
values,
errors,
touched,
handleChange,
handleBlur,
handleSubmit
}) => (
<form onSubmit={handleSubmit}>
<label className="form-label label" name="email">Email</label>
<br />
<input
className="form-control form-control-lg input"
type="email"
name="email"
onChange={handleChange}
onBlur={handleBlur}
value={values.email}
/>
{errors.email && touched.email && errors.email}
<br />
<label className="form-label label " name="password">Password</label>
<br />
<input
className="form-control form-control-lg input"
type="password"
name="password"
onChange={handleChange}
onBlur={handleBlur}
value={values.password}
/>
{errors.password && touched.password && errors.password}
<br />
<button type="submit" className="btn btn-danger">
Submit
</button>
</form>
)}
</Formik>
</div>
</div>
)
}
export default Login;
它还会从 App.js 获取 IsAuth propr,以防用户第一次进入页面并且没有保存令牌。
我看到的问题是 token
状态最初是错误的。 useEffect
在渲染周期结束时运行,因此对于初始渲染 token
是 false
const [token, setToken] = useState(false);
useEffect(() => {
if (localStorage.getItem("token") === null) {
setToken(false);
} else {
setToken(true);
}
}, []);
并且使用 token
状态呈现的任何 Route
将使用此初始 false
值并相应地执行操作。
<Route path="/seeker" element={token ? <Seeker /> : <Navigate to="/" />} />
如果在 "/seeker"
路径上并且 token
值为 false
,则呈现 Navigate
组件。
假设您的所有身份验证流程都正确且有效并将 token
值设置到 localStorage,那么您应该从 [=35] 初始化 token
状态 =] localStorage.
const initializeState = () => !!JSON.parse(localStorage.getItem("token"));
const [token, setToken] = useState(initializeState);