浅谈React-router v6 实现登录验证流程

 更新时间:2022年05月29日 09:40:53   作者:椒盐味花生米  
本文主要介绍了React-router v6 实现登录验证流程,主要介绍了公共页面、受保护页面和登录页面,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友们下面随着小编来一起学习学习吧

此示例演示了一个包含三个页面的简单登录流程:公共页面、受保护页面和登录页面。 为了查看受保护的页面,你必须先登录。
首先,访问公共页面。 然后,访问受保护的页面。 你尚未登录,因此你将被重定向到登录页面。 登录后,你将被重定向回受保护的页面。

封装 Context 包裹容器

首先封装AuthProvider组件,利用Context特性共享那些对于一个组件树而言是“全局”的数据。
全局定义usersignInsignOut数据和方法,signInsignOut使用了高阶函数,也方便后续扩展和修改。

Context主要应用场景在于很多不同层级的组件需要访问同样一些的数据。请谨慎使用,因为这会使得组件的复用性变差。
如果你只是想避免层层传递一些属性,组件组合(component composition)有时候是一个比 Context更好的解决方案。

import { ReactNode, createContext, useState } from "react";

export interface AuthContextType {
  user: any;
  signIn: (user: string, callback: VoidFunction) => void;
  signOut: (callback: VoidFunction) => void;
}

export let AuthContext = createContext<AuthContextType | null>(null);

const fakeAuthProvider = {
  isAuthenticated: false,
  signIn(callback: VoidFunction) {
    this.isAuthenticated = true;
    setTimeout(callback, 100);
  },
  signOut(callback: VoidFunction) {
    this.isAuthenticated = false;
    setTimeout(callback, 100);
  },
};

const AuthProvider = ({ children }: { children: ReactNode }) => {
  const [user, setUser] = useState<any>(null);

  let signIn = (newUser: string, callback: VoidFunction) => {
    return fakeAuthProvider.signIn(() => {
      setUser(newUser);
      callback();
    });
  };

  let signOut = (callback: VoidFunction) => {
    return fakeAuthProvider.signOut(() => {
      setUser(null);
      callback();
    });
  };

  return (
    <AuthContext.Provider value={{ user, signIn, signOut }}>
      {children}
    </AuthContext.Provider>
  );
};

export default AuthProvider;

封装 Layout 父级容器

Layout组件主要是针对登录状态进行校验,然后做相应处理。利用react-router v6中<Outlet />组件显示嵌套路由,相比于v5版本v6实现嵌套路由更加方便,省略了很多冗余的判断代码。

import { useContext } from "react";
import { useNavigate, Link, Outlet } from "react-router-dom";
import { AuthContext, AuthContextType } from "../AuthProvider";

const useAuth = () => useContext(AuthContext);

const AuthStatus = () => {
  let auth = useAuth();
  let { user, signOut } = auth as AuthContextType;
  let navigate = useNavigate();

  if (!user) return <p>没有登录</p>;
  return (
    <>
      <p>你好 {user}! </p>
      <button onClick={() => signOut(() => navigate("/"))}>退出</button>
    </>
  );
};

const Layout = () => {
  return (
    <div>
      <AuthStatus />
      <ul>
        <li>
          <Link to="/">公共页面</Link>
        </li>
        <li>
          <Link to="/protected">受保护页面</Link>
        </li>
      </ul>
      <Outlet />
    </div>
  );
};

export default Layout;

开发 Login 模块

import { useContext, FormEvent } from "react";
import { useNavigate, useLocation, Location } from "react-router-dom";
import { AuthContext, AuthContextType } from "../AuthProvider";

interface State extends Omit<Location, "state"> {
  state: {
    from: {
      pathname: string;
    };
  };
}

const useAuth = () => useContext(AuthContext);

const Login = () => {
  let auth = useAuth();
  let { signIn } = auth as AuthContextType;
  const { state } = useLocation() as State;
  let from = state.from.pathname || "/";
  let navigate = useNavigate();

  const handleSubmit = (event: FormEvent<HTMLFormElement>) => {
    event.preventDefault();

    let formData = new FormData(event.currentTarget);
    let username = formData.get("username") as string;

    signIn(username, () => navigate(from, { replace: true }));
  };

  return (
    <div>
      <p>您必须登录才能查看该页面 {from}</p>

      <form onSubmit={handleSubmit}>
        <label>
          用户名: <input name="username" type="text" />
        </label>
        <button type="submit">登录</button>
      </form>
    </div>
  );
};

export default Login;

开发 Protected 包裹容器

主要就是对登录状态进行校验,成功则渲染子组件,否则跳转回登录页面

import { useContext } from "react";
import { useLocation, Navigate } from "react-router-dom";
import { AuthContext, AuthContextType } from "../AuthProvider";

const useAuth = () => useContext(AuthContext);

const RequireAuth = ({ children }: { children: JSX.Element }) => {
  let auth = useAuth();
  let { user } = auth as AuthContextType;
  let location = useLocation();

  if (!user) return <Navigate to="/login" state={{ from: location }} replace />;

  return children;
};

export default RequireAuth;

App 入口文件

入口文件没有对路由进行懒加载优化,因为是小应用,所以实际开发还是要考虑性能优化的。

import { Routes, Route } from "react-router-dom";

import AuthProvider from "src/views/AuthProvider";
import Layout from "src/views/auth/layout";
import LoginPage from "src/views/auth/login";
import PublicPage from "src/views/auth/publicPage";
import RequireAuth from "src/views/auth/requireAuth";
import ProtectedPage from "src/views/auth/protectedPage";

const App = () => {
  return (
    <AuthProvider>
      <Routes>
        <Route element={<Layout />}>
          <Route path="/" element={<PublicPage />} />
          <Route path="/login" element={<LoginPage />} />
          <Route
            path="/protected"
            element={
              <RequireAuth>
                <ProtectedPage />
              </RequireAuth>
            }
          />
        </Route>
      </Routes>
    </AuthProvider>
  );
};

export default App;

到此这篇关于浅谈React-router v6 实现登录验证流程的文章就介绍到这了,更多相关React-router登录验证内容请搜索脚本之家以前的文章或继续浏览下面的相关文章希望大家以后多多支持脚本之家!

相关文章

  • react-router-domV6版本的路由和嵌套路由写法详解

    react-router-domV6版本的路由和嵌套路由写法详解

    本文主要介绍了react-router-domV6版本的路由和嵌套路由写法详解,文中通过示例代码介绍的非常详细,具有一定的参考价值,感兴趣的小伙伴们可以参考一下
    2022-03-03
  • react lazyLoad加载使用详解

    react lazyLoad加载使用详解

    lazy是React提供的懒(动态)加载组件的方法,React.lazy(),路由组件代码会被分开打包,能减少打包体积、延迟加载首屏不需要渲染的组件,依赖内置组件Suspense标签的fallback属性,给lazy加上loading指示器组件,Suspense目前只和lazy配合实现组件等待加载指示器的功能
    2023-03-03
  • React+CSS 实现绘制横向柱状图

    React+CSS 实现绘制横向柱状图

    这篇文章主要介绍了React+CSS 实现绘制横向柱状图,文章围绕主题展开详细的内容介绍,具有一定的参考价值,需要的小伙伴可以参考一下
    2022-09-09
  • 详解React 元素渲染

    详解React 元素渲染

    这篇文章主要介绍了React 元素渲染的相关资料,文中示例代码非常详细,帮助大家更好的理解和学习,感兴趣的朋友可以了解下
    2020-07-07
  • React实现随机颜色选择器的示例代码

    React实现随机颜色选择器的示例代码

    颜色选择器是一个用于选择和调整颜色的工具,它可以让用户选择他们喜欢的颜色,本文主要介绍了React实现随机颜色选择器的示例代码,具有一定的参考价值,感兴趣的可以了解一下
    2023-12-12
  • 详解React项目中eslint使用百度风格

    详解React项目中eslint使用百度风格

    这篇文章主要介绍了React项目中eslint使用百度风格,本文给大家介绍的非常详细,对大家的学习或工作具有一定的参考借鉴价值,需要的朋友可以参考下
    2021-09-09
  • 详解React native全局变量的使用(跨组件的通信)

    详解React native全局变量的使用(跨组件的通信)

    本篇文章主要介绍了详解React native全局变量的使用(跨组件的通信),具有一定的参考价值,有兴趣的同学可以了解一下
    2017-09-09
  • React 如何向url中添加参数

    React 如何向url中添加参数

    这篇文章主要介绍了React 如何向url中添加参数,具有很好的参考价值,希望对大家有所帮助。如有错误或未考虑完全的地方,望不吝赐教
    2022-08-08
  • React onClick/onChange传参(bind绑定)问题

    React onClick/onChange传参(bind绑定)问题

    这篇文章主要介绍了React onClick/onChange传参(bind绑定)问题,具有很好的参考价值,希望对大家有所帮助。如有错误或未考虑完全的地方,望不吝赐教
    2023-02-02
  • 浅谈react路由传参的几种方式

    浅谈react路由传参的几种方式

    这篇文章主要介绍了浅谈react路由传参的几种方式,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友们下面随着小编来一起学习学习吧
    2021-03-03

最新评论