我正在构建一个带有登录/注册系统的MERN应用程序,但我无法将用户重定向到确认页面,然后提示他们登录。
似乎我可以在 react-router-dom 中使用useHistory
钩子,并在我的 axios 请求中执行history.push()
,该请求在我的寄存器函数中:
function handleRegister(e) {
let history = useHistory();
e.preventDefault();
// Grab state
const user = {
username: formState.username,
email: formState.email,
password: formState.password,
password2: formState.password2,
};
// Post request to backend
axios
.post("http://localhost:4000/register", user)
.then((res) => {
// Redirect user to the /thankyouForRegistering page which prompts them to login.
history.push("/thankyouForRegistering");
})
.catch((err) => {
console.log(err);
});
}
但这行不通。我收到一个错误,说:
React Hook "useHistory" is called in function "handleRegister" which is neither a React function component or a custom React Hook function
经过进一步的研究,似乎为了使用 useHistory 钩子,它必须在<Router>
范围内(可能?(或直接在 onClick 处理程序上。
所以像这样:
<Button onClick={() => history.push()}></button>
不过,我真的不能这样做,因为我没有使用 onClick 作为我的注册按钮,我使用的是 onSubmit 和我自己的注册函数。
我也考虑使用<Redirect />
,所以我尝试制作一个名为authorized
的新状态,在我的 axios 请求中将授权状态设置为 true,然后尝试这样做:
<Route
path="/thankyouForRegistering"
render={() => (
authorized ? (
<ThankyouForRegistering />
) : (
<Redirect to="/register" />
))
}
/>
但这也不起作用,它也不会给我任何错误。
有谁知道在注册/登录时将用户重定向到新页面的最佳方法?我已经为此苦苦挣扎了两个星期。
谢谢!!
编辑:这是整个组件 - 它有点混乱,但如果有人需要任何解释,请告诉我。
import React, { useState } from "react";
import {
BrowserRouter as Router,
Switch,
Route,
Redirect,
useHistory,
} from "react-router-dom";
let navMenu;
function App() {
let history = useHistory();
const [navMenuOpen, setNavMenuOpen] = useState(false);
const [loggedIn, setLoggedIn] = useState(false);
const [errorMsg, setErrorMsg] = useState("");
const [token, setToken] = useState("");
const [authorized, setAuthorized] = useState(false);
const initialState = {
username: "",
email: "",
password: "",
password2: "",
};
const [formState, setFormState] = useState(initialState);
const { username, email, password, password2 } = formState;
const handleChange = (e) => {
setFormState({ ...formState, [e.target.name]: e.target.value });
};
function handleRegister(e) {
//const history = useHistory();
e.preventDefault();
// Grab setState
const user = {
username: formState.username,
email: formState.email,
password: formState.password,
password2: formState.password2,
};
// Post request to backend
axios
.post("http://localhost:4000/register", user)
.then((res) => {
console.log(user);
history.push("/thankyouForRegistering");
setAuthorized(true);
// Redirect user to the /thankyouForRegistering page which prompts them to login.
})
.catch((err) => {
console.log(err);
});
// Once a user has registered, clear the registration form and redirect the user to a page that says thank you for registering, please login.
}
const handleLogin = (e) => {
e.preventDefault();
// Grab setState
const userData = {
email: formState.email,
password: formState.password,
};
axios
.post("http://localhost:4000/login", userData)
.then((res) => {
// Get token from local storage if there is a token
localStorage.setItem("token", res.data.token);
// If there is a token, redirect user to their profile and give them access to
// their recipeList and shoppingList
setLoggedIn(true);
//props.history.push("/profile");
})
.catch((err) => console.log(err));
};
const navMenuToggle = () => {
console.log("toggle");
setNavMenuOpen(!navMenuOpen);
};
const navMenuClose = () => {
setNavMenuOpen(false);
};
const logoutFromNavMenu = () => {
setLoggedIn(false);
navMenuClose();
};
return (
<Router>
<div>
<Navbar
loggedIn={loggedIn}
navMenuToggle={navMenuToggle}
/>
<NavMenu
loggedIn={loggedIn}
show={navMenuOpen}
navMenuClose={navMenuClose}
logoutFromNavMenu={logoutFromNavMenu}
/>
<Switch>
<Route
path="/login"
render={(props) => (
<Login
handleLogin={handleLogin}
handleChange={handleChange}
email={email}
password={password}
errorMsg={errorMsg}
/>
)}
/>
<Route
path="/register"
render={(props) => (
<Register
handleRegister={handleRegister}
handleChange={handleChange}
email={email}
username={username}
password={password}
password2={password2}
errorMsg={errorMsg}
/>
)}
/>
<Route
path="/profile"
render={() => (loggedIn ? <Profile /> : <Redirect to="/login" />)}
/>
<Route
path="/thankyouForRegistering"
render={() =>
authorized ? (
<ThankyouForRegistering />
) : (
<Redirect to="/register" />
)
}
/>
<Route
path="/recipes"
render={(props) =>
loggedIn ? <RecipeBook /> : <Redirect to="/login" />
}
/>
<Route
path="/list"
render={(props) =>
loggedIn ? <ShoppingList /> : <Redirect to="/login" />
}
/>
<Route path="/about" component={About} />
<Route path="/contact" component={Contact} />
<Route
path="/accountSettings"
render={(props) =>
loggedIn ? <AccountSettings /> : <Redirect to="/login" />
}
/>
<Route
exact
path="/"
component={() => <Home isLoggedIn={loggedIn} />}
/>
</Switch>
</div>
</Router>
);
}
export default App;
我想出了问题所在。仅仅使用useHistory是不够的,我必须使用withRouter才能访问历史记录道具。
所以我用路由器导入到我的应用程序组件:
import { withRouter } from 'react-router-dom';
然后在页面底部的 App 功能正下方添加了这个:
const AppWithRouter = withRouter(App);
export default AppWithRouter;
因此,该应用程序现在必须导出为withRouter的参数才能访问历史记录(以及我认为的位置和参数?
但这仍然不够。它给了我一个错误,说withRouter只能在<Router />
(或<BrowserRouter />
,无论您使用哪个(内使用。所以我用索引包装了我的主要<App />
.js并附上<BrowserRouter />
ReactDOM.render(
<BrowserRouter>
<App />
</BrowserRouter>,
document.getElementById("root")
);
当然是进口的。
不过,这仍然不够。添加后
history.push("/thankYouForRegistering);
对于我的 Axios 请求,它将路由添加到 URL,但没有重新呈现视图。它仍然停留在注册页面上。然后我意识到我现在在两个不同的地方<BrowserRouter />
。在我的 App 组件中,我仍然将其包裹在我的所有路由上,因此在删除它并返回一个div 并包裹<Switch />
我的所有路由后,它使它按预期工作。
我希望这对面临相同问题的人有所帮助!