【问题标题】:ReactJS: Redirecting to a new page within an axios requestReactJS:在 axios 请求中重定向到新页面
【发布时间】:2020-09-06 02:29:35
【问题描述】:

我正在构建一个带有登录/注册系统的 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 和我自己的注册功能。

我也考虑过使用&lt;Redirect /&gt;,所以我尝试创建一个名为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;

【问题讨论】:

  • 移动你的行 let history = useHistory();将它从你的函数中移出到反应组件中。
  • 除此之外,请显示您的组件定义,而不仅仅是其中的内容。
  • 当我从我的函数中添加 let history = useHistory() 时,它给了我这个错误:“错误:无效的钩子调用。只能在函数组件的主体内部调用钩子。 "
  • 刚刚发布了整个组件。
  • 嘿 HappyPanda,你试过用 props.history.push 代替 useHistory() 吗?

标签: javascript reactjs axios react-hooks react-router-dom


【解决方案1】:

我发现了问题所在。使用 useHistory 是不够的,我必须使用 withRouter 才能访问 history 属性。

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

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

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

const AppWithRouter = withRouter(App);

export default AppWithRouter;

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

但这还不够。它给了我一个错误,说 withRouter 只能在&lt;Router /&gt;(或&lt;BrowserRouter /&gt;,无论您使用哪个)中使用。所以我用&lt;BrowserRouter /&gt;将我的主要&lt;App /&gt;包裹在index.js中

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

当然是导入了。

不过,这还不够。添加后

history.push("/thankYouForRegistering); 

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

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

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2020-04-06
    • 1970-01-01
    • 2018-12-18
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2014-02-14
    • 2019-05-20
    相关资源
    最近更新 更多