首页 > 解决方案 > ReactJS:在 axios 请求中重定向到新页面

问题描述

我正在构建一个带有登录/注册系统的 MERN 应用程序,但我无法将用户重定向到确认页面,然后提示他们登录。

似乎我可以useHistory在 react-router-dom 中使用钩子并history.push()在我的注册函数中的 axios 请求中执行:

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 和我自己的注册功能。

我还研究了 using <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;

标签: javascriptreactjsaxiosreact-hooksreact-router-dom

解决方案


我弄清楚了问题所在。使用 useHistory 是不够的,我必须使用 withRouter 才能访问 history 道具。

所以我将 withRouter 导入到我的 App 组件中:

import { withRouter } from 'react-router-dom';

然后将其添加到页面的最底部,就在 App 功能的正下方:

const AppWithRouter = withRouter(App);

export default AppWithRouter;

所以现在必须将 App 作为 withRouter 的参数导出才能访问历史道具(以及我认为的位置和参数?)

但这还不够。它给了我一个错误,说 withRouter 只能在<Router />(或<BrowserRouter />,无论您使用哪个)内使用。所以我把我的 main 包裹<App />在 index.js 中<BrowserRouter />

 ReactDOM.render(
  <BrowserRouter>
    <App />
  </BrowserRouter>,
  document.getElementById("root")
);

当然是进口的。

不过,这还不够。添加后

history.push("/thankYouForRegistering); 

对于我的 axios 请求,它添加了到 URL 的路由,但它没有重新呈现视图。它仍然停留在注册页面上。然后我意识到我现在<BrowserRouter />在两个不同的地方。在我的 App 组件中,我仍然将它包裹在我的所有路线上,因此在删除它并返回一个<Switch />包裹着我所有路线的 div 之后,这使它按预期工作。

我希望这对面临同样问题的人有所帮助!


推荐阅读