成功登录后到达路由器重定向

时间:2020-04-14 18:20:57

标签: reactjs react-redux react-router reach-router

我想使用react和reach router完成登录。本质上,在成功认证后,我想从Login Component转到HomeLayout Component。我已经成功登录

这是我的App组件的代码,这是项目的入口点

import React, { Component } from 'react';

function App() {
    return (
      <div>
        <Login />
      </div>
    );
  }

===============

登录组件

  import React, { Component } from "react";
import axios from "axios"

class Login extends Component {
    state = {
      username: "",
      password: "",
      loggedIn: false
    }

    onChange = (e) => {
      e.preventDefault()
     this.setState({
        [e.target.name]:e.target.value
      })    
    }

     LoginUser = (e)=>{
      const {username, password} = this.state
       e.preventDefault()
      let UserLoginDetails = {
        email: username,
        password: password
      }

       axios.post("localhost:4500/users/login", UserLoginDetails)
       .then(loginResultFromBackend=>{
          this.setState({loggedIn: true})
              // I want to go to "/Home" here
       }).catch(error=>{
         console.log(error)
       })
     }

    render() {
      return (
        <form onSubmit={this.LoginUser}>
        <input
            type="text"
            value={this.state.username}
            name="username"
            onChange={this.onChange}/>

        <input
            type="text"
            value={this.state.username}
            name="username"
            onChange={this.onChange}/>

        <button type="submit">Submit</button>
    </form>
      );
    }
  }

===========================

家庭组件

import category from "./category";
import { Router, Link } from "@reach/router";
import NotFound404 from "../default404/PageNotFound";


 class HomeLayout extends Component {
   render() {
     return (
       <div>
           <Link to={`Home`} > Home </Link>
           <Link to={`category`}  Categories </Link>


         <Router>
           <Home path="/Home"></Home>
           <category path={`category/:category`}></category>
           <NotFound404 default />
         </Router>
       </div>
     );
   }
 }

在该状态下,我已经设置了username =“”,password =“”,并且loginIn = false。

预期行为

从后端获得结果后,我想导航到/ Home上的Home页面。

我尝试做navigate("/Home"),但这只是更改了URL,而没有更改组件。

在这里帮我吗?如果从反应路由器方面来的人有所了解,那将很有用,因为我本质上是代码新手。

4 个答案:

答案 0 :(得分:1)

import { Redirect } froom "react-router-dom";



render() {
  if (this.state.loggedIn) return <Redirect to="/Home" />;
  return (
    <form onSubmit={this.LoginUser}>
    <input
        type="text"
        value={this.state.username}
        name="username"
        onChange={this.onChange}/>

    <input
        type="text"
        value={this.state.username}
        name="username"
        onChange={this.onChange}/>

    <button type="submit">Submit</button>
</form>
  );
}

答案 1 :(得分:0)

如果react-router-dom为true,则从this.state.loggedIn导入重定向组件,并使用它来重定向到主页。您可以在react-router-dom和“到达”路由器上使用它。

答案 2 :(得分:0)

如果“ 登录”组件用作

,则可以直接使用this.props.history.push("/Home");
<Switch>
    <Route path="/Login" component={Login} />
    <Route path="/Home" component={Home} />
</Switch>

因此,您可以将其写为

axios.post("localhost:4500/users/login", UserLoginDetails)
.then(loginResultFromBackend=>{
    this.setState({loggedIn: true})
    this.props.history.push("/Home");
}).catch(error=>{
    console.log(error)
})

此外,您可以尝试使用LINK

中提到的useHistory

答案 3 :(得分:0)

这是你的做法。我将使用 2 个 React Hook 分享它:

  1. useGoToLogin(回调 - 如果您想将其与按钮或操作一起使用 - 您也可以使用 useEffect 来实现着陆效果):
import { navigate, useLocation } from "@reach/router";
import { useCallback } from "react";
import { useAuth } from "../auth";
import { routes } from "../utilities";

/**
 * This can be passed as a prop vs using a const in case you have multiple paths
 * you'd like to redirect it to, but let's keep it simple.
 * we w
 */
// routes.login =>7 "/login"
const LOGIN_PATH = routes.login;

/**
 * This will redirect you to a login page and will pass
 * a "redirect" query param so you can redirect the user later.
 */

type GoToLoginProps = {
  callbackIfAuthenticated?(): void;
};

export function useGoToLogin(props?: GoToLoginProps) {
  /**
   * This can be extracted or omitted. THis simply checks if
   * the user is authenticated or not. I have defined a useAuth hook
   * that uses React context to handle all of the authentication.
   *
   * This is not defined in this post.
   * You can also pass this as a prop (if you want to make the hook
   * pure - e.g: no internal dependencies)
   */
  const { authenticated } = useAuth();
  // The <Location></Location> component must be passed at the top of the
  // Component tree as it uses React.Context
  const location = useLocation();

  // Note, "redirect" will be used in useRedirect hook. You can create this
  // as a const variable.
  const loginBack = `?redirect=${location.pathname}`;
  const callbackIfAuthenticated = props?.callbackIfAuthenticated;
  return useCallback(() => {
    if (authenticated) {
      callbackIfAuthenticated?.();
      return;
    }
    navigate(LOGIN_PATH + loginBack);
  }, [authenticated, loginBack, callbackIfAuthenticated]);
}


  1. useRedirect
import { navigate, useLocation } from "@reach/router";
import { useCallback, useMemo } from "react";

/**
 * This will redirect a user from a path to something else.
 *
 * Be very careful on allowing any redirects as you can let the user
 * be exposed to an Open Redirect Vulnerability. Always try to redirect using
 * local or whitelisted urls!
 *
 * I am going to be sharing this with local URLs only!
 */
type RedirectProps = {
  defaultPath: string;
};
export function useRedirect(props?: RedirectProps) {
  // The <Location></Location> component must be passed at the top of the
  // Component tree as it uses React.Context
  const { search } = useLocation();

  const params = useMemo(() => new URLSearchParams(search), [search]);
  const defaultPath = props?.defaultPath;
  return useCallback(() => {
    const redirect = params.get("redirect");
    // If it doesn't exist, then exit the function.
    if (!redirect || !verifyLocalUrl(redirect)) {
      defaultPath && navigate(defaultPath);
      return;
    }

    // The dot (.) symbolizes relativeness to the base path "/"
    navigate("." + redirect);
  }, [params, defaultPath]);
}

/**
 *
 * I am no security expert, so I don't know which are the problems with this approach.
 * We make a simple, yet powerful check which will verify if the
 * user has a malicious intent and has sent a full URL within the login.
 * (Open Redirect Attacks).
 *
 * We check if the verifyLocalUrl is an URL. If it is, then it WON'T throw.
 * If it isn't it will throw a TypeError and we can safely assume it's not a url.
 *
 * In addition, we also check if the URL has a dot (.) because malformed URLs such as
 * "mybadsite.se" are still valid and will fail the URL check.
 * @param redirect
 * @returns
 */
function verifyLocalUrl(redirect: string) {
  try {
    if (redirect?.indexOf(".") !== -1) {
      return false;
    }

    new URL(redirect);
    return false;
  } catch (e) {
    return true;
  }
}

然后,您将如何使用它们:

第一。如果未通过身份验证,您希望将它们重定向到的页面中。

  const test = useCallback(() => window.alert("Put any function you'd like to execute in case the user is authenticated"), []);
  const bookConsult = useGoToLogin({ callbackIfAuthenticated: test });
  <button onClick={bookConsult}>Proceed If Authenticated - Book Consult</button>

然后,在您的登录组件中:

export const Login = () => {
 const auth = useAuth();

 const redirect = useRedirect({ defaultPath: "/" });

 const login = async (values) => {
  const loginResult = auth.login(values.username, values.password);
  if(loginResult.error) {
    return;
  }
  redirect();
}
 return (
   <>
    {/**Login here */}
    <button onClick={login}>Login </button>
   </>
 )
}
  1. 记得在树中添加 <LocationProvider></LocationProvider>
function App() {
   return (
      <LocationProvider>
        <Root />
      </LocationProvider>);
   }