十年匠心定制 · 商业建站与技术教学双线并行 咨询热线:400-886-1026 service@lmnt.cn
ARTICLE DETAIL

资讯详情

深耕网站建设与运营推广的一线实战洞察。

Reflex 客户端存储指南:使用 rx.Cookie、rx.LocalStorage 与 rx.SessionStorage 持久化浏览器状态

Reflex 客户端存储指南:使用 rx.Cookie、rx.LocalStorage 与 rx.SessionStorage 持久化浏览器状态 Reflex 客户端存储指南使用 rx.Cookie、rx.LocalStorage 与 rx.SessionStorage 持久化浏览器状态【免费下载链接】reflex️ Web apps in pure Python 项目地址: https://gitcode.com/GitHub_Trending/re/reflex本文基于 docs/client_storage/overview.md 及配套的 浏览器存储 API 参考 编写。Reflex 允许把状态变量直接映射到浏览器的 Cookie、localStorage 与 sessionStorage从而在会话之间、不同标签页之间持久化用户偏好、认证凭据等数据。读完本文你将掌握三种客户端存储类型的完整参数、默认行为、跨标签页同步、数据清理事件以及用 pydantic 序列化复杂结构的最佳实践并了解其在 Reflex 编译器中的底层实现。为什么需要客户端存储传统的 Reflex 状态State默认由服务端持有页面刷新或关闭浏览器后即丢失。而浏览器提供了三种可以记住数据的机制Cookie随 HTTP 请求自动发送到服务端适合认证令牌等需要服务端读取的数据localStorage持久化在浏览器中除非被显式删除否则一直存在适合用户偏好与应用级状态sessionStorage与当前标签页/窗口的生命周期绑定关闭标签页即清除适合临时性、会话内的数据。使用浏览器本地存储可以让用户偏好、认证 Cookie、以及其他零散信息保存在客户端并且从不同的浏览器标签页访问——这正是 overview.md 一开头描述的核心能力。客户端存储 Var 的核心机制在 Reflex 中一个客户端存储变量client-side storage var看起来、用起来都和普通的str变量一模一样唯一的区别在于其默认值的类型决定了数据存储在哪里默认值为rx.Cookie→ 存储为浏览器 Cookie默认值为rx.LocalStorage→ 存储到 localStorage默认值为rx.SessionStorage→ 存储到 sessionStorage。存储键key的命名默认取自变量名也可以通过关键字参数namemy_custom_name覆盖例如class ClientStorageState(rx.State): my_cookie: str rx.Cookie() my_local_storage: str rx.LocalStorage() custom_cookie: str rx.Cookie(nameCustomNamedCookie, max_age3600)从源码看这三类存储对象都继承自同一个基类ClientStorageBasereflex/istate/storage.py其options()方法会把所有非None的配置项转成驼峰命名的字典供前端编译使用而Cookie、LocalStorage、SessionStorage本身又都是str的子类storage.py因此它们天然具备字符串变量的全部能力只是额外携带了存储配置。入门示例三个输入框的跨会话持久化overview.md给出了一个最直观的演示在输入框中输入内容然后在另一个标签页重新打开页面或打开浏览器开发者工具的 Storage 面板就能看到值已经被保存在浏览器中。import reflex as rx class ClientStorageState(rx.State): my_cookie: str rx.Cookie() my_local_storage: str rx.LocalStorage() custom_cookie: str rx.Cookie(nameCustomNamedCookie, max_age3600) rx.event def set_my_cookie(self, value: str): self.my_cookie value rx.event def set_my_local_storage(self, value: str): self.my_local_storage value rx.event def set_custom_cookie(self, value: str): self.custom_cookie value def client_storage_example(): return rx.vstack( rx.hstack( rx.text(my_cookie), rx.input( valueClientStorageState.my_cookie, on_changeClientStorageState.set_my_cookie, ), ), rx.hstack( rx.text(my_local_storage), rx.input( valueClientStorageState.my_local_storage, on_changeClientStorageState.set_my_local_storage, ), ), rx.hstack( rx.text(custom_cookie), rx.input( valueClientStorageState.custom_cookie, on_changeClientStorageState.set_custom_cookie, ), ), )这段代码展示了三个关键点状态变量用rx.Cookie()/rx.LocalStorage()作为默认值声明事件处理器与普通状态变量完全一致直接对变量赋值即可custom_cookie通过nameCustomNamedCookie指定了浏览器侧的存储键名并设置了max_age36001 小时后过期。rx.Cookie认证与服务端可读状态rx.Cookie表示一个存储为浏览器 Cookie 的状态变量目前仅支持字符串值。参数说明参数含义默认值name客户端 Cookie 的名称变量名pathCookie 的路径使用/可让 Cookie 在所有页面可访问/max_age相对最大存活时间秒自客户端接收到时起算None浏览器会话结束即过期domainCookie 的域如sub.domain.com或.allsubdomains.comNonesecure是否仅通过 HTTPS 传输Nonesame_site是否随第三方请求发送可选True/False/None/lax/strictlax这些默认值均可以在 storage.py 中Cookie.__new__的签名 中找到对应实现。示例class CookieState(rx.State): c1: str rx.Cookie() c2: str rx.Cookie(c2 default) # 自定义配置的 Cookie c3: str rx.Cookie(max_age2) # 2 秒后过期 c4: str rx.Cookie(same_sitestrict) c5: str rx.Cookie(path/foo/) # 仅在 /foo/ 下可访问 c6: str rx.Cookie(namec6-custom-name)两个重要约定默认值是第一个位置参数。rx.Cookie、rx.LocalStorage、rx.SessionStorage都把默认值作为第一个位置参数传入如rx.LocalStorage(light)。它不能作为关键字参数传入——关键字参数name、max_age、sync等只用于配置存储行为。Cookie 的默认值永远不会在浏览器中被设置。Cookie 值只在变量被赋值时才会真正写入。如果确实需要设置默认值可以在on_load事件处理器中给 Cookie 赋值rx.event def load(self): if self.my_cookie : self.my_cookie default value访问 Cookie 与其他状态的注意点Cookie 与普通状态变量一样被访问。如果其他状态需要读取某个 Cookie应让该状态成为定义 Cookie 状态的子状态或者使用get_stateAPI 访问。渲染 Cookie 时直接导入定义它的状态并在前端引用即可。另外两个独立的状态应避免定义同名的rx.Cookie虽然技术上可行但两者的 Cookie 选项可能不同导致意外结果而且在一个状态中更新 Cookie 值不会自动同步到另一个状态除非发生页面刷新或导航事件。删除 Cookie使用rx.remove_cookie(key)删除浏览器中的 Cookierx.button(Remove cookie, on_clickrx.remove_cookie(key))也可以从事件处理器中返回该事件典型的登出场景class CookieState(rx.State): ... def logout(self): return rx.remove_cookie(auth_token)rx.LocalStorage跨标签页共享的用户偏好rx.LocalStorage表示存储到浏览器 localStorage 的状态变量仅支持字符串值。参数说明参数含义默认值name客户端存储键的名称变量名sync布尔值是否在同一浏览器的标签页之间保持同步Falseclass LocalStorageState(rx.State): # 默认配置 l1: str rx.LocalStorage() # 自定义配置 l2: str rx.LocalStorage(l2 default) l3: str rx.LocalStorage(namel3) # 跨标签页自动同步 l4: str rx.LocalStorage(syncTrue)跨标签页同步Syncing Vars由于 localStorage 属于整个浏览器所有 LocalStorage 变量天然在所有标签页之间共享。sync参数控制的是当某个标签页更新值时是否主动传播到其他标签页而无需用户执行导航或刷新页面。删除与清空# 删除单个键 rx.button( Remove Local Storage, on_clickrx.remove_local_storage(key), ) # 清空全部 localStorage注意可能影响同一域名下的其他应用或第三方库 rx.button( Clear all Local Storage, on_clickrx.clear_local_storage(), )rx.remove_local_storage也可以从事件处理器中返回例如登出时移除认证令牌return rx.remove_local_storage(local_storage_state.l1)。rx.SessionStorage会话级临时数据rx.SessionStorage表示存储到 sessionStorage 的状态变量仅支持字符串值。它与 localStorage 类似但数据会在页面会话结束时清除关闭浏览器或标签页。参数说明参数含义默认值name客户端存储键的名称变量名class SessionStorageState(rx.State): # 默认配置 s1: str rx.SessionStorage() # 自定义配置 s2: str rx.SessionStorage(s2 default) s3: str rx.SessionStorage(names3)会话持久性Session Persistence一个页面会话的持续时间等于浏览器打开的时长它会跨越页面刷新与恢复但在关闭标签页或浏览器时被清除。与 localStorage 不同SessionStorage按标签页/窗口隔离同一源origin下的其他标签页/窗口无法共享其中的数据。删除与清空# 删除单个键 rx.button( Remove Session Storage, on_clickrx.remove_session_storage(key), ) # 清空全部 sessionStorage可能影响同一域名下的其他应用或第三方库 rx.button( Clear all Session Storage, on_clickrx.clear_session_storage(), )同样可以从事件处理器返回移除事件return rx.remove_session_storage(session_storage_state.s1)。复杂数据的序列化策略三种存储类型目前都仅支持字符串值。如果需要在其中存放非平凡的数据结构就必须在存取前后自行序列化。官方推荐的做法是使用pydantic 类承载数据——它提供简单的序列化辅助方法并且能递归处理复杂的嵌套对象结构。下面是一个把用户设置存入 localStorage 的完整示例import reflex as rx import pydantic class AppSettings(pydantic.BaseModel): theme: str light sidebar_visible: bool True update_frequency: int 60 error_messages: list[str] pydantic.Field(default_factorylist) class ComplexLocalStorageState(rx.State): data_raw: str rx.LocalStorage({}) data: AppSettings AppSettings() settings_open: bool False rx.event def save_settings(self): self.data_raw self.data.model_dump_json() self.settings_open False rx.event def open_settings(self): self.data AppSettings.model_validate_json(self.data_raw) self.settings_open True rx.event def set_field(self, field, value): setattr(self.data, field, value) def app_settings(): return rx.form.root( rx.foreach( ComplexLocalStorageState.data.error_messages, rx.text, ), rx.form.field( rx.flex( rx.form.label( Theme, rx.input( valueComplexLocalStorageState.data.theme, on_changelambda v: ComplexLocalStorageState.set_field( theme, v ), ), ), rx.form.label( Sidebar Visible, rx.switch( checkedComplexLocalStorageState.data.sidebar_visible, on_changelambda v: ComplexLocalStorageState.set_field( sidebar_visible, v ), ), ), rx.form.label( Update Frequency (seconds), rx.input( valueComplexLocalStorageState.data.update_frequency, on_changelambda v: ComplexLocalStorageState.set_field( update_frequency, v ), ), ), rx.dialog.close(rx.button(Save, typesubmit)), gap2, directioncolumn, ) ), on_submitlambda _: ComplexLocalStorageState.save_settings(), )核心模式存储层用一个str类型的rx.LocalStorage({})变量保存 JSON 字符串业务层用一个 pydantic 模型变量data: AppSettings保存真实数据保存时model_dump_json()序列化写入存储读取时model_validate_json()反序列化还原表单字段通过set_field事件按字段名动态更新 pydantic 对象的属性。三种存储类型的对比与选型特性rx.Cookierx.LocalStoragerx.SessionStorage持久性直到 Cookie 过期直到被显式删除直到浏览器/标签页关闭存储上限约 4KB约 5MB约 5MB随请求发送是否否可访问性服务端与客户端仅客户端仅客户端过期机制可配置永不会话结束作用域可配置域、路径源域名标签页/窗口跨标签页同步否是syncTrue否典型用途认证、服务端状态用户偏好、应用状态临时会话数据何时使用 rx.Cookie数据需要在服务端访问Cookie 随 HTTP 请求发送处理用户认证需要对过期时间与作用域做精细控制需要把数据限制在应用的特定路径下。何时使用 rx.LocalStorage需要存储较大体积的数据约 5MB 以内数据需要无限期保留直到被显式删除需要在应用的不同标签页/窗口之间共享数据需要记住跨浏览器会话的用户偏好。何时使用 rx.SessionStorage需要关闭浏览器/标签页即清除的临时数据需要把数据隔离在特定标签页/窗口中存储不应在会话结束后留存的敏感信息实现表单草稿、购物车、多步骤流程等按会话划分的功能需要让某个状态在 Redis 过期后继续存活服务端状态需要比 Redis TTL 存活更久时。底层原理Reflex 如何编译客户端存储了解实现细节有助于排查问题和写出更健壮的代码。客户端存储的处理贯穿编译与状态生命周期两个环节。编译阶段收集所有客户端存储变量在 reflex/compiler/utils.py 中compile_client_storage递归遍历整个状态树_compile_client_storage_field判断字段默认值或字段类型是否为Cookie/LocalStorage/SessionStorage之一并调用options()取出配置_compile_client_storage_recursive按状态全名 变量名生成存储键如state_name.var_name并跳过继承变量只收集当前状态自己定义的字段最终结果分为 cookies、local_storage、session_storage 三组字典在 compiler.py 处作为client_storage注入编译产物前端据此生成读写逻辑。这也解释了为什么子状态中定义的客户端存储变量也能正常工作——编译是递归的子状态、孙状态的存储字段都会被收集。状态生命周期hydrate 时重置客户端存储在 reflex/state.py 中_is_client_storage用于判断某个字段是否为客户端存储变量检查默认值是否继承自ClientStorageBase_reset_client_storage会在hydrate水合阶段把客户端存储变量重置为默认值。其注释说明这样做的目的是——当用户在浏览器中清除了 Cookie 后后端也能同步重置对应的值避免前后端状态不一致。这意味着每次页面加载hydrate时客户端存储变量都会先复位到默认值随后由浏览器侧的真实存储值覆盖从而保证以浏览器为唯一事实来源source of truth。测试验证仓库中的集成测试 tests/integration/test_client_storage.py 覆盖了本指南涉及的大部分行为默认配置与自定义配置的 Cookiemax_age、same_site、path、自定义name、带默认值的 localStorage、syncTrue的跨标签页同步变量、sessionStorage 的默认与自定义命名以及子状态和孙状态中定义存储变量的场景。如果你要基于本指南实现自己的存储逻辑可以参考该测试文件作为行为基准。小结声明即持久化把状态变量默认值设为rx.Cookie/rx.LocalStorage/rx.SessionStorage即可零成本获得浏览器持久化能力变量读写方式与普通字符串变量完全一致键名可控存储键默认取变量名可用name覆盖字符串限制三种存储仅支持字符串复杂结构请用 pydantic 模型 JSON 序列化Cookie 特殊默认值不会写入浏览器需要时在on_load中赋值两个状态避免定义同名 Cookie选型依据需要服务端读取选 Cookie需要跨标签页长期共享选 LocalStorage配合syncTrue需要会话级隔离选 SessionStorage清理手段每种存储都有对应的remove_*移除单键事件localStorage 与 sessionStorage 还有clear_*清空全部的事件。相关源码与文档API 参考 docs/api-reference/browser_storage.md、存储类实现 reflex/istate/storage.py、编译逻辑 reflex/compiler/utils.py、状态重置 reflex/state.py、集成测试 tests/integration/test_client_storage.py。【免费下载链接】reflex️ Web apps in pure Python 项目地址: https://gitcode.com/GitHub_Trending/re/reflex创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考
返回列表