使用 React Router V6 了解会话管理

使用 React Router V6 了解会话管理

Photo by 约书亚阿拉贡 on 不飞溅

React 根本不需要任何介绍,在这里我不打算描述它是什么以及如何工作的。我试图更详细地介绍 React 应用程序架构的主要方面,这将在未来帮助您快速构建一个易于扩展的项目。我们已经准确地开发了使用 React Router v6 构建应用程序的架构部分。

另外,我将使用 样式化组件 并且在文章的最后,您可以获取到存储库的 GitHub 链接。

应用结构

在开始任何编程操作之前,最好准确地确定应用程序中将涉及的所有路由。使用一些图表计划可以更好地进行研究,您可以在其中查看应用程序的整体概况。

此外,重要的是要明确哪些路线必须受到保护。保护是指用户只有在获得授权的情况下才能访问特定路由。如果你没有被授权,换句话说没有登录,那么你就不能访问那个路由。

也是重定向的一个非常重要的部分。例如,如果你有授权,如果你要去家乡路线,会发生什么?你应该被重定向到哪里?所有这些 重定向规则 应在开始时识别。让我们看一下带有应用程序路由模式的图表。

路由结构示意图

最初,区分受保护的和公共的路线很重要。这里绿色表示公共,红色表示受保护。此外,您可以找到一些带有受保护路径的绿色框,这意味着这些受保护的路径将具有不同的重定向逻辑。

如果您进入第二步注册而没有在第一步提供日期,则必须在第一步进行重定向。

作品

导航在所有路线中都很常见,但取决于 会议 .如果用户获得授权,链接堆栈将有所不同。这样,所有路线都可以更好地结束 主布局 您将在哪里拥有生命周期和会话注入的逻辑,当然还有在标题导航中显示的内容。重要的是要了解状态取决于授权。

布局

在我们的例子中,所有 看法 组件除了 未找到 导航 组件取决于 会议 .这意味着将显示 装载机 在暴露组件之前,以便清楚要呈现的内容。文件夹结构包含一堆用于进行 API 调用的组件、常量和伪造品。

 应用程序架构样板  
 ├── package.json  
 └── 源  
 ├── App.js  
 ├── __mocks__  
 │ └── db.mock.js  
 ├── 组件  
 │ ├── Footer.js  
 │ ├── Loading.js  
 │ ├── MainLayout.js  
 │ ├── Navigation.js  
 │ ├── ProtectedRoute.js  
 │ └── PublicRoute.js  
 ├── 常数  
 │ └── index.js  
 ├── 假的  
 │ ├── fakeApi.js  
 │ └── fakeCache.js  
 ├── 挂钩  
 │ └── useSession.js  
 └── index.js

数据请求

如您所见,我们将为我们的应用程序使用假 API。实际上,它可以是 Apollo 客户端或 REST API 调用,但在我们的例子中,我们将使用 承诺 暂停 为了 1s 请求延迟。我们必须处理登录和注销的身份验证,并从虚假 API 请求当前会话。最终,它是一个包含大量有用方法的简单类。

'src/__mocks__/db.mock'导入{db};  
 从'./fakeCache'导入{ fakeCache }; 类 FakeApi {  
 静态请求时间 = 1000;  
 静态 KEY_CACHE = '缓存';  
 静态数据库 = 数据库; 上下文 = {}; 构造函数(){  
 常量上下文 = fakeCache.getItem(FakeApi.KEY_CACHE);  
 如果(上下文){  
 this.context = 上下文;  
 }  
 } 静态 userById = id => FakeApi.DB.find(user => user.id === id); #asyncRequest = 回调 =>  
 新的承诺(解决 => {  
 设置超时(()=> {  
 常量结果 = 回调();  
 解决(结果);  
 }, FakeApi.REQUEST_TIME);  
 }); 获取会话(){  
 返回 this.#asyncRequest(() => this.context.session);  
 } 登录() {  
 this.context.session = FakeApi.userById(1);  
 fakeCache.setItem(FakeApi.KEY_CACHE, this.context);  
 返回 this.getSession();  
 } 登出() {  
 this.context = {};  
 fakeCache.clear();  
 返回这个。#asyncRequest(() => null);  
 }  
 } 出口 const fakeApi = new FakeApi();

您可以在 构造函数 我们正在使用缓存。这是因为我们的请求必须有一个用于响应的缓存,并使用缓存作为下一个请求的提前以提高性能。这个实现非常粗略和简单,但很容易理解它的要点。

流程是,一旦我们调用,我们必须创建一个会话,并且 登出 同时清除会话和缓存。每个 异步请求 应该有一个 REQUEST_TIME 作为我们请求的假延迟。但是缓存呢?

 出口常量 fakeCache = {  
 获取项目(键){  
 返回 JSON.parse(localStorage.getItem(key));  
 }, 设置项(键,值){  
 localStorage.setItem(key, JSON.stringify(value));  
 }, 清除() {  
 localStorage.clear();  
 },  
 };

对于存储/缓存数据,我们将使用 本地存储 .这只是一个带有方法的简单对象,没有别的。

路由

路由器部分必须关心我们 私人的 上市 路线。重定向必须从 私人的 当我们试图访问 /登录 如果用户在没有会话的情况下转到某个私有路由,它必须重定向到 /登录 .

 "/" // -> 主视图取决于会话  
 "/about" // -> 关于显示有会话和无会话  
 "/login" // -> 仅显示无会话登录  
 "/signup" // -> 仅在没有会话的情况下注册节目  
 "/forgot-password" // -> 只显示没有会话的忘记密码  
 "/account" // -> 用户只显示会话  
 "/settings" // -> 设置只显示会话  
 "/posts" // -> 帖子和嵌套路由仅显示会话  
 "*" // -> Not Found 显示完全没有依赖关系

您可以看到针对每条路线的评论描述了可访问性的行为。进去的理由是什么 报名 如果你已经有一个会话?我在其他项目中多次看到这个问题。所以,在我们的例子中,我们将有一个重定向和从 受保护的路由 并从 公共路线 .仅有的 未找到视图 最后应该有完全的访问权限。

 <Routes>  
 <Route element={<MainLayout /> }>  
 <Route path="/" element={<HomeView /> } />  
 <Route path="/about" element={<AboutView /> } />  
 <Route  
 路径="/登录"  
 元素={ <PublicRoute element={<LoginView /> } />}  
 />  
 <Route  
 路径="/注册"  
 元素={ <PublicRoute element={<SignUpView /> } />}  
 />  
 <Route  
 路径="/忘记密码"  
 元素={ <PublicRoute element={<ForgotPasswordView /> } />}  
 />  
 <Route  
 路径="/帐户"  
 元素={  
 <ProtectedRoute  
 元素={ <ProtectedRoute element={<UserView /> } />}  
 />  
 }  
 />  
 <Route  
 路径="/设置"  
 元素={ <ProtectedRoute element={<SettingsView /> } />}  
 />  
 <Route path="/posts" element={<ProtectedRoute /> }>  
 <Route index element={<PostsView /> } />  
 <Route path=":uuid" element={<PostView /> } />  
 </Route>  
 </Route>  
 <Route path="*" element={<NotFoundView /> } />  
 </Routes>

如您所见,我们为这两个流添加了保护。 受保护的路由 将导航到 /登录 在没有会话的情况下 公共路线 将重定向到 / , 因为 主页查看 必须检查授权。

 常量 HomeView = () => {  
 常量会话 = useOutletContext();  
 返回会话数据?<ListsPostsView /><LandingView /> ;  
 };

会议 可以得到正确的形式 使用OutletContext() 这是因为 主布局 将提供 语境 .

主要布局

一切都包裹在 主布局 这将提供 语境 会议 和其他全球相关数据。为了 主布局 我们将使用常见的 路线 和下 出口 将公开所有路线。让我们看一下设置。

 常量 MainLayout = ({ 导航 }) => {  
 常量会话 = useSession(); 返回 (  
 <StyledMainLayout>  
 {!session.loading ? (  
 <div>  
 <Navigation session={session} navigate={navigate} />  
 <StyledContainer isLoggedIn={!!session.data}>  
 <Outlet context={session} />  
 </StyledContainer>  
 </div>  
 ) : (  
 <Loading />  
 )}  
 <Footer />  
 </StyledMainLayout>  
 );  
 };

页脚 没有状态依赖,我们将一直渲染它。但 导航 并且所有嵌套路由都必须能够访问 会议 .这里是 出口 渲染子路由元素以及在哪里传递 语境 给所有的孩子。

向我们提供的请求 会议 数据有延迟响应,在这种情况下,我们显示 正在加载 零件。

会议

当应用程序被挂载时,我们必须请求当前 会议 .这 使用会话 钩子会在坐骑上开火并获得 会议 来自缓存或 API。

 导出 const useSession = () => {  
 常量缓存 = fakeCache.getItem(SESSION_KEY);  
 const [数据,setData] = useState(缓存);  
 const [加载,setLoading] = useState(false); 使用效果(()=> {  
 如果(!缓存){  
 设置加载(真);  
 }  
 假API  
 .getSession()  
 .then(会话 => {  
 如果(会话){  
 设置数据(会话);  
 fakeCache.setItem(SESSION_KEY, session);  
 } 别的 {  
 设置数据(空);  
 fakeCache.clear();  
 }  
 })  
 .finally(() => {  
 设置加载(假);  
 });  
 }, []); 返回{数据,setData,加载};  
 };

每一个 假API 请求我们将响应存储到缓存中,例如存储在真实网站中的 cookie。然后是时候展示取决于 会议 导航 登录 / 登出 和子组件。

导航

国家为 导航 在当前请求期间启用或禁用按钮很重要。如果打 登出 最好禁用所有按钮,以防止会话清除期间的其他操作。

 导出常量导航 = ({ 导航,会话 }) => {  
 常量 [isLoading, setLoading] = useState(false); 常量 onLogin = async () => {  
 设置加载(真);  
 const sessionData = await fakeApi.login();  
 session.setData(sessionData);  
 fakeCache.setItem(SESSION_KEY, sessionData);  
 设置加载(假);  
 导航('/');  
 }; 常量 onLogout = async () => {  
 设置加载(真);  
 fakeCache.clear();  
 等待 fakeApi.logout();  
 session.setData(null);  
 设置加载(假);  
 导航('/');  
 }; 返回 (  
 <StyledNavigation>  
 <Link to="/"></Link>  
 {会话数据? (  
 <div>  
 <Link to="/posts">帖子</Link>  
 <Link to="/settings">设置</Link>  
 <Link to="/account">我的简历</Link>  
 <button disabled={isLoading} onClick={onLogout}>  
 {正在加载? “正在加载...”:“注销”}  
 </button>  
 </div>  
 ) : (  
 <div>  
 <Link to="/about">关于</Link>  
 <Link to="/signup">报名</Link>  
 <button disabled={isLoading} onClick={onLogin}>  
 {正在加载? '加载中...' : '登录'}  
 </button>  
 </div>  
 )}  
 </StyledNavigation>  
 );  
 };

私人和公共

很明显,路由应该受到保护,具体取决于 会议 ,但如何得到 语境 在每个路由组件中?我们仍将借助上下文 使用OutletContext() 由...提供 反应路由器 API。

 出口 const ProtectedRoute = ({ element }) => {  
 常量会话 = useOutletContext();  
 返回会话数据? (  
 元素 ||<Outlet />  
 ) : (  
 <Navigate to="/login" replace />  
 );  
 };

为了 公共路线 一切都几乎相同,但另一种方式是使用不同的重定向路线。

 出口 const PublicRoute = ({ element }) => {  
 常量会话 = useOutletContext();  
 返回会话数据?<Navigate to="/" replace /> : 元素 ||<Outlet /> ;  
 };

可能你可以看到,最好有类似的东西 智能路线 哪里最好只提供重定向的路线和道具来识别它是 上市 或者 私人的 .为了将来的可扩展性,我更喜欢分离这样的逻辑。差不多就是这样。

结论

React Router 是 React 应用程序最流行的路由解决方案,为当今的开发人员提供了最明显和最清晰的 API。由于上一个版本的惊人更新,构建路由架构变得更加容易和方便。希望应用程序的这种结构旨在帮助快速构建未来 React 项目的主体。谢谢你。

版权声明:本文为博主原创文章,遵循 CC 4.0 BY-SA 版权协议,转载请附上原文出处链接和本声明

本文链接:https://www.qanswer.top/17410/00490600

posted @   哈哈哈来了啊啊啊  阅读(80)  评论(0编辑  收藏  举报
相关博文:
阅读排行:
· 无需6万激活码!GitHub神秘组织3小时极速复刻Manus,手把手教你使用OpenManus搭建本
· Manus爆火,是硬核还是营销?
· 终于写完轮子一部分:tcp代理 了,记录一下
· 别再用vector<bool>了!Google高级工程师:这可能是STL最大的设计失误
· 单元测试从入门到精通
点击右上角即可分享
微信分享提示