发布于 2026-01-06 7 阅读
0

如何以及为什么应该将 React UI 状态存储在 URL 中?DEV 的全球展示与分享挑战赛,由 Mux 呈现:展示你的项目!

如何以及为何应该将 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。这种模式对网络用户来说非常自然——自从万维网诞生以来,分享链接就一直是其不可或缺的一部分!

这是一张带有注释的谷歌搜索页面截图。搜索词输入框已高亮显示,箭头指向URL中存储该搜索词的对应部分。搜索结果已筛选,仅显示过去一周的搜索结果,另一个箭头指向URL中存储此数据的对应部分。

单页应用(SPA)出现后,由于不再需要向服务器发出请求来更改屏幕上显示的内容(因此得名单页应用),我们就无需在URL中存储这些数据了。但这很容易导致我们失去网络体验中一个独特的方面——可分享链接。

桌面和移动应用从来没有真正标准化的方式来链接到应用的特定部分,而现代的深度链接实现依赖于网络上的URL。因此,当我们构建功能更接近原生应用的Web应用时,为什么要放弃我们已经使用了几十年的URL深度链接功能呢?

极其简单的深度链接

构建包含多个页面的 Web 应用时,至少应该在显示不同页面时更改 URL,例如 `<page>`/login和 `<page> /home`。在 React 生态系统中,React Router非常适合此类客户端路由,而Next.js是一个功能齐全的优秀 React 框架,也支持服务器端渲染。

但我说的是深度链接,指的是点击几次鼠标、输入几次键盘后,用户界面状态的精确还原。对于注重效率的网页应用来说,这绝对是一项杀手级功能,因为它允许用户即使在关闭应用或与他人共享后,也能立即返回到之前的操作位置,从而无缝衔接,继续工作。

屏幕录制显示模态窗口打开的过程,导致 URL 更新并添加 `#modal=`

注意,当模态框打开时,URL 如何更新以添加 `#modal="webhooks"`。

你可以使用像query-string这样的 npm 包,并编写一个基本的 React Hook 来将 URL 查询参数同步到你的状态,并且有很多相关教程,但是有一个更直接的解决方案。

在为我们的 React 应用Rowy的架构重写探索现代 React 状态管理库时,我偶然发现了Jotai ,这是一个受 React 团队的Recoil库启发的基于原子的微型状态库

这种模型的主要优势在于,状态原子独立于组件层级结构,可以在应用程序的任何位置进行操作。这解决了 React Context 导致不必要的重新渲染的问题,我之前曾用其他方法解决这个问题。你可以在useRefJotai 的文档中了解更多关于原子状态概念的信息,也可以在Recoil 的文档中找到更技术性的版本

代码

Jotai 有一种名为 的原子类型atomWithHash,它将状态原子同步到 URL 哈希。

假设我们想将模态框的打开状态存储在 URL 中。首先,我们创建一个原子:

import { atomWithHash } from "jotai/utils";
export const modalOpenAtom = atomWithHash("modalOpen", false);
view raw atoms.ts hosted with ❤ by GitHub

然后,在模态组件本身中,我们可以像这样使用这个原子useState

它的样子是这样的:

屏幕录制显示模态框打开的过程,此时 URL 会更新以反映 UI 状态,并在末尾添加 #modalOpen=true。模态框关闭时,URL 会替换为 modalOpen=false。

就是这样!就这么简单。

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}

屏幕录像显示了通过深度链接打开 Rowy 演示 Web 应用程序,并打开云日志模态框的过程。

解码 URL 组件可以揭示 React 中使用的确切状态:

这样做的一个副作用atomWithHash是,它默认会将状态推送到浏览器历史记录中,因此用户可以点击后退和前进按钮在 UI 状态之间切换。

屏幕录像显示用户反复点击浏览器中的后退按钮,导致用户界面状态发生变化,模态框不断打开和关闭。

此行为是可选的,可以使用以下replaceState选项禁用:


感谢阅读!我希望这篇文章能让您相信,应该在 URL 中公开更多 UI 状态,这样既方便分享,又能减少用户的操作阻力——尤其是在实现起来非常简单的情况下。

您可以在 Twitter 上关注我@nots_dney,获取更多关于前端工程的文章和推文。

GitHub 标志 rowyo / rowy

低代码后端平台。在类似电子表格的用户界面上管理数据库,并在浏览器中使用 JS/TS 构建云函数工作流。

✨ 类似 Airtable 的数据库管理界面 ✨ 无需编写代码,即可构建任何自动化流程 ✨

连接数据库,无需离开浏览器即可使用低代码创建云函数。
专注于构建您的应用程序。适用于 Firebase 和 Google Cloud 的低代码

在线演示🛝

💥 在实时演示环境中体验 Rowy 💥

特色✨

20211004-RowyWebsite.mp4

功能强大的 Firestore 电子表格界面

  • Firestore 的 CMS
  • CRUD 操作
  • 批量导入或导出数据 - CSV、JSON、TSV
  • 按行值排序和筛选
  • 锁定、冻结、调整大小、隐藏和重命名列
  • 同一系列的多种视图

利用云函数和现成的扩展程序实现自动化

  • 基于字段级数据变更构建云函数工作流
    • 使用任何 NPM 模块或 API。
  • 使用预置代码块连接到您最喜欢的工具,或者创建您自己的代码块。
    • SendGrid、Algolia、Twilio、BigQuery 等

丰富且灵活的数据字段





文章来源:https://dev.to/notsidney/how-and-why-you-should-store-react-ui-state-in-the-url-34pi