如何以及为何应该将 React UI 状态存储在 URL 中
由 Mux 主办的 DEV 全球展示挑战赛:展示你的项目!
React 中的深度链接,就像 useState 一样简单
你是否曾经使用过功能繁多、包含模态窗口或侧边栏的复杂网页应用?经过几次点击浏览不同页面后,你终于找到了想要的信息,但却不小心关闭了标签页?(或者Windows系统自动更新了?)
如果能有一种方法可以不用经历同样繁琐的过程就能回到之前的状态,那就太好了。或者,如果能共享这个状态,让队友也能和你一起做同样的事情,那就更好了。
这个问题可以通过深度链接来解决,深度链接目前在移动应用中被广泛用于打开应用的特定页面或用户界面状态。但为什么很多网页应用却没有采用这种技术呢?
⏭ 点击此处直接跳至解决方案和代码片段。
恢复网页深度链接
单页应用程序 (SPA) 的出现使我们能够打造全新的、即时交互式的 Web 用户体验。通过在客户端使用 JavaScript 进行更多操作,我们可以立即响应用户事件,例如打开自定义对话框窗口或使用类似 Google Docs 的实时文本编辑器。
传统的服务器端渲染网站每次都会发送请求来获取一个新的 HTML 页面。谷歌就是一个很好的例子,它会向服务器发送一个包含用户搜索查询的 URL: https://www.google.com/search? q=your+query+here 。这种模式的优点在于,如果我筛选过去一周的搜索结果,只需分享 URL 即可分享相同的搜索查询: https://www.google.com/search?q =react+js&tbs=qdr:w 。这种模式对网络用户来说非常自然——自从万维网诞生以来,分享链接就一直是其不可或缺的一部分!
单页应用(SPA)出现后,由于不再需要向服务器发出请求来更改屏幕上显示的内容(因此得名单页应用 ),我们就无需在URL中存储这些数据了 。但这很容易导致我们失去网络体验中一个独特的方面——可分享链接。
桌面和移动应用从来没有真正标准化的方式来链接到应用的特定部分,而现代的深度链接实现依赖于网络上的URL。因此,当我们构建功能更接近原生应用的Web应用时,为什么要放弃我们已经使用了几十年的URL深度链接功能呢?
极其简单的深度链接
构建包含多个页面的 Web 应用时,至少应该在显示不同页面时更改 URL,例如 `<page>` /login和 `<page> /home`。在 React 生态系统中, React Router 非常适合此类客户端路由,而 Next.js 是一个功能齐全的优秀 React 框架,也支持服务器端渲染。
但我说的是 深度 链接,指的是点击几次鼠标、输入几次键盘后,用户界面状态的精确还原。对于注重效率的网页应用来说,这绝对是一项杀手级功能,因为它允许用户即使在关闭应用或与他人共享后,也能立即返回到之前的操作位置,从而无缝衔接,继续工作。
注意,当模态框打开时,URL 如何更新以添加 `#modal="webhooks"`。
你可以使用像 query-string这样的 npm 包,并编写一个基本的 React Hook 来将 URL 查询参数同步到你的 状态 ,并且有 很多 相关 的 教程 ,但是有一个更直接的解决方案。
在为我们的 React 应用 Rowy 的架构重写探索现代 React 状态管理库时,我偶然发现了 Jotai ,这是一个受 React 团队的 Recoil 库启发的基于原子的微型状态库 。
这种模型的主要优势在于,状态原子独立于组件层级结构,可以在应用程序的任何位置进行操作。这解决了 React Context 导致不必要的重新渲染的问题,我 之前曾用其他方法解决这个问题。你可以在 useRefJotai 的文档 中了解更多关于原子状态概念的信息,也可以在 Recoil 的文档 中找到更技术性的版本 。
代码
Jotai 有一种名为 的原子类型 atomWithHash,它将状态原子同步到 URL 哈希。
假设我们想将模态框的打开状态存储在 URL 中。首先,我们创建一个原子:
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters. Learn more about bidirectional Unicode characters
import { atomWithHash } from "jotai/utils" ;
export const modalOpenAtom = atomWithHash ( "modalOpen" , false ) ;
然后,在模态组件本身中,我们可以像这样使用这个原子 useState:
它的样子是这样的:
就是这样!就这么简单。
Jotai 的强大之处 atomWithHash在于它可以存储任何数据 useState,并且会自动将对象字符串化以存储在 URL 中。因此,我可以将更复杂的状态存储在 URL 中,使其可以共享。
在 Rowy 中,我们使用这项技术实现了云日志的用户界面。我们正在构建一个开源平台,旨在简化后端开发并消除常见工作流程中的摩擦。因此,减少日志共享的摩擦对我们来说至关重要。您可以在我们的演示中看到它的实际应用,我可以为您提供一个特定部署日志的链接: https://demo.rowy.io/table/roadmap#modal="cloudLogs"&cloudLogFilters={"type"%3A"build"%2C"timeRange"%3A{"type"%3A"days"%2C"value"%3A7}%2C"buildLogExpanded"%3A1}
解码 URL 组件可以揭示 React 中使用的确切状态:
这样做的一个副作用 atomWithHash是,它默认会将状态推送到浏览器历史记录中,因此用户可以点击后退和前进按钮在 UI 状态之间切换。
此行为是可选的,可以使用以下 replaceState选项 禁用:
感谢阅读!我希望这篇文章能让您相信,应该在 URL 中公开更多 UI 状态,这样既方便分享,又能减少用户的操作阻力——尤其是在实现起来非常简单的情况下。
您可以在 Twitter 上关注我 @nots_dney, 获取更多关于前端工程的文章和推文。
低代码后端平台。在类似电子表格的用户界面上管理数据库,并在浏览器中使用 JS/TS 构建云函数工作流。
✨ 类似 Airtable 的数据库管理界面 ✨ 无需编写代码,即可构建任何自动化流程 ✨
连接数据库,无需离开浏览器即可使用低代码创建云函数。 专注于构建您的应用程序。适用于 Firebase 和 Google Cloud 的低代码
在线演示🛝
💥 在实时演示环境 中体验 Rowy 💥
特色✨
20211004-RowyWebsite.mp4
功能强大的 Firestore 电子表格界面
Firestore 的 CMS
CRUD 操作
批量导入或导出数据 - CSV、JSON、TSV
按行值排序和筛选
锁定、冻结、调整大小、隐藏和重命名列
同一系列的多种视图
利用云函数和现成的扩展程序实现自动化
基于字段级数据变更构建云函数工作流
使用预置代码块连接到您最喜欢的工具,或者创建您自己的代码块。
SendGrid、Algolia、Twilio、BigQuery 等
丰富且灵活的数据字段
文章来源:https://dev.to/notsidney/how-and-why-you-should-store-react-ui-state-in-the-url-34pi