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

目录
  • 封装 Context 包裹容器
  • 封装 Layout 父级容器
  • 开发 Login 模块
  • 开发 Protected 包裹容器
  • App 入口文件

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

封装 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登录验证内容请搜索我们以前的文章或继续浏览下面的相关文章希望大家以后多多支持我们!

(0)

相关推荐

  • react-router-dom v6 通过outlet实现keepAlive 功能的实现

    本文主要介绍了react-router-dom v6 通过outlet实现keepAlive 功能的实现,具体如下: keepAlive代码: import React, { useRef, useEffect, useReducer, useMemo, memo } from 'react' import { TransitionGroup, CSSTransition } from 'react-transition-group' import { useLocation } from 'r

  • 详解react-router-dom v6版本基本使用介绍

    目录 Routes Route Navigate NavLink useRoutes 嵌套路由 路由传参 编程式导航 Routes 代替Switch组件,不会向下匹配 用来包裹Route Route 必须被Routes组件包裹 component属性变成element caseSensitive 路径大小写敏感属性,默认是不敏感(访问/about = /ABOUT) index 与path属性是互斥的,index表示为当前路由的根 可以用作layout组件,不写element属性,写了要与 Ou

  • React Router V6更新内容详解

    目录 ReactRouterV6变更介绍 1.<Switch>重命名为<Routes> 2.<Route>的新特性变更 3.嵌套路由变得更简单 3.1具体变化有以下: 3.2废弃了V5中的Redirect 3.3多个<Routes/> 4.用useNavigate代替useHistory 5.Hooks中新钩子useRoutes代替react-router-config 总结 React Router V6 变更介绍 之前一直在用5.x版本的Router,突

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

    目录 1-单级路由 2-嵌套路由(about路径进行嵌套) ReactRouterv6使用路由嵌套和重定向 1 - 单级路由 <NavLink to="/home">Home</NavLink> <NavLink to="/about">about</NavLink> <Routes>   <Route path='/home' element={<Home/>}/>   <R

  • react-router-dom V6的配置使用实践

    目录 一.关于书写方面 二.路由的嵌套方面优化 三.关于路由的灵活配置化 四.关于路由鉴权方面 最近在搭建PC项目的React框架,涉及到React Router,开发同学有时就需要去尝试点新的东西,在开发过程中才不会枯燥的,基于这个理念推动,就在搭建的时候用V6的版本开始了(虽然只是个新版本,也不算啥新东西)...... V6的版本相对于V5,做了很多的优化,有书写方面的.路由的嵌套.路由配置化.鉴权方面等等,下面就简单的介绍下如何使用 一.关于书写方面 路由注册的时候由的Switch改为了R

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

    目录 封装 Context 包裹容器 封装 Layout 父级容器 开发 Login 模块 开发 Protected 包裹容器 App 入口文件 此示例演示了一个包含三个页面的简单登录流程:公共页面.受保护页面和登录页面. 为了查看受保护的页面,你必须先登录.首先,访问公共页面. 然后,访问受保护的页面. 你尚未登录,因此你将被重定向到登录页面. 登录后,你将被重定向回受保护的页面. 封装 Context 包裹容器 首先封装AuthProvider组件,利用Context特性共享那些对于一个组件

  • 使用React Router v6 添加身份验证的方法

    目录 开始 基础路由 创建受保护的路由 使用嵌套路由和< Outlet /> 结尾 React Router v6是React应用程序的一个流行且功能强大的路由库.它提供了一种声明式的.基于组件的路由方法,并能处理URL参数.重定向和加载数据等常见任务. 这个最新版本的React Router引入了很多新概念,比如<Outlet />和layout布局路由,但相关文档仍然很少. 本文将演示如何使用React Router v6创建受保护的路由以及如何添加身份验证. 开始 打开终端,

  • 浅谈React Router关于history的那些事

    如果你想理解React Router,那么应该先理解history.更确切地说,是history这个为React Router提供核心功能的包.它能轻松地在客户端为项目添加基于location的导航,这种对于单页应用至关重要的功能. npm install --save history 存在三类history,分别时browser,hash,与 memory.history包提供每种history的创建方法. import { createBrowserHistory, createHashHi

  • 浅谈React多个setState会调用几次

    目录 1. 两个setState,调用几次? 2. 两个setState,调用的是哪一个? 3. 两个setState放在setTimeout中? 4. 总结 1. 两个setState,调用几次? 如下代码所示,state中有一个count.对按钮绑定了点击事件,事件中执行了两次setState,每次都将count的值加1. 当点击按钮时,setState会执行几次?render()会执行几次? 答案:都是1次. state = { count: 0 }; handleClick = () =

  • 浅谈React 中的浅比较是如何工作的

    React 中浅比较的概念无处不在,它在不同的流程中起着关键的作用,也可以在React组件的多个生命周期中找到.比如,React Hooks中的依赖数组,通过React.memo进行记忆.在React的官方文档中也多次提到“浅比较”这个概念,下面我们就来看看React中的浅比较是如何工作的! 想要理解浅比较的概念,最直接的方法就是研究React的源代码,下面就来看看React中的shallowEqual.js 文件: import is from './objectIs'; import has

  • 浅谈React 属性和状态的一些总结

    一.属性 1.第一种使用方法:键值对 <ClaaNameA name = "Tom" /> <ClaaNameA name = {Tom} /> <ClaaNameA name = {"Tom"} /> <ClaaNameA name = {[1,2,3]} />//数组 <ClaaNameA name = {FunctionNAme} /> //定义一个函数 2.第二种方法:三个点的展开对象形式 var

  • 浅谈react.js中实现tab吸顶效果的问题

    在react项目开发中有一个需求是,页面滚动到tab所在位置时,tab要固定在顶部. 实现的思路其实很简单,就是判断当滚动距离scrollTop大于tab距离页面顶部距离offsetTop时,将tab的position变为fixed. 在react中,我在state中设置一个navTop属性,切换这个属性的值为true或者false,然后tab标签使用classnames()这个方法来利用navTop的值添加类名fixed. 一开始我是这样写的: import cs from 'classnam

  • 浅谈react+es6+webpack的基础配置

    这是模块化开发.主流框架和最新版的ECMAScript语法规范的一个小demo 准备工作 安装 nodeJs 首先进入node官网,去下载最新版的nodeJs webpack 安装webpack npm install webpack -g 参数-g表示全局安装webpack,你在cmd命令中哪个文件夹下都可以使用webpack的命令,如果不加-g的话,是只可以在你安装webpack的目录下使用webpack这个命令 webpack 也有一个 web 服务器 npm install webpac

  • 浅谈react.js 之 批量添加与删除功能

    最近做的CMS需要用到批量添加图片的功能:在添加文件的容器盒子内,有两个内容,分别是:添加按钮与被添加的选择文件组件. 结构分析: 被添加的组件,我们称为:UploadQiNiuFiles(七牛文件上传组件),含一个删除当前组件的删除按钮 添加按钮的事件 被添加组件存放的容器 做这个效果只需要明白三个方法的用途就OK: 直接绑定要删除组件的  deleteType(),它是调用删除index数量的方法  removeContent() //删除{qiniu}与{deleteQiNiu}内容,是把

  • 浅谈React Native打包apk的坑

    RN的打包,大家可以根据官网一步一步来,但这里有几个地方注意,一下简单介绍: 生成一个签名密钥 在项目的目录下打开cmd命令窗口输入一下命令运行: keytool -genkey -v -keystore my-release-key.keystore -alias my-key-alias -keyalg RSA -keysize 2048 -validity 10000 这条命令会要求你输入密钥库(keystore)和对应密钥的密码,然后设置一些发行相关的信息.最后它会生成一个叫做my-re

随机推荐