Blazor:如何存储页面状态(所有组件状态)?

Posted

技术标签:

【中文标题】Blazor:如何存储页面状态(所有组件状态)?【英文标题】:Blazor: how to store page state (all components states)? 【发布时间】:2021-04-18 13:09:56 【问题描述】:

我有 1 个完整的页表组件(自定义,带有列过滤器、排序、动态加载、“无限”滚动等),然后用户单击一行上的“编辑”操作,它导航到编辑项目页面。再次,整页。这是一个要求,它应该在视觉上是单独的页面。 2 个原因:用户所做的一项重要任务是搜索,表越大,数据越多 - 越好。第二个任务是更新一些记录。单个记录是一个非常、非常、非常复杂的数据集,它确实需要尽可能多的屏幕空间。

问题是当用户完成编辑记录时,应用导航到上一页,但表格被重置,默认过滤、排序和滚动位置。

好吧,我可以从表格组件中提取数据并将其存储在“伪会话”服务数据中。问题是我必须向表格组件添加大量代码 - 加载/保存状态方法。真的很多工作(对于每个列过滤器元素,然后是列过滤器行)。

但是有一个更简单的方法。而不是使用单独的页面,我可以伪造它。将表格和行编辑表单放在同一个页面上,然后用 JS/CSS 隐藏一个部分。这应该可行,但是 IDK,对我来说似乎是一个丑陋的黑客。你渲染两个部分,显示一个。

顺便说一句,如果您在.razor 文件中隐藏服务器端的组件,然后再次显示它 - 它会被重置。将调用构造函数,将所有参数设置为默认初始值。

有没有办法在服务器端隐藏渲染的片段,然后在不导致 Blazor 重新初始化的情况下显示它?

或者是一个“返回”功能,它以与导航发生前完全相同的状态显示最后一页?

更新: 我刚刚测试了隐藏选项。作为魅力发挥作用。方法如下:

<div style="@("display: " + (CurrentView == ViewOptions.List ? "block" : "none"))">
    @* My list view here... *@
</div>
@if (CurrentView == ViewOptions.Edit) 
    @* My edit entry view here... *@

其中ViewOptions 只是一个包含可能视图的enumCurrentView 的类型为 ViewOptions。当CurrentView 设置为List 时,第一部分可见,第二部分根本不渲染。当它改变时,第一部分被隐藏(但不被销毁),第二部分被初始化并渲染。由于我的表单已经作为单独的组件完成,它们将行标识符作为参数,并且它们触发自己的事件,允许在用户完成它们时将 CurrentView 切换回列表。所以我们基本上在 1 页上有 2 个虚拟页面。一个hacky的解决方案,但它有效。我在 30 分钟内完成了这项工作,而不是花费几个小时向我的 DataTable 组件添加加载/保存功能。

不过,也许还有更好的方法?或者也许它是最佳的?比如...我们有页面(彼此不直接相关)和... SUBPAGES,就像在视觉上是分开的,但在逻辑上与其父页面直接相关。

这让我有了一个想法……如果我制作了一个名为Subpage 的组件会怎样? :) Blazor 中已经有一个名为Page 的组件。所以它想完成页面和子页面的整个概念。当页面不直接相关时 - 导航“返回”到上一页没有多大意义。甚至维护无关页面的状态。但是子页面是直接相关的。它的内容取决于父页面的状态。 IDK,也许走那条路太疯狂了;)

【问题讨论】:

【参考方案1】:

TL;DR:我认为,您走的是正确的省力之路。

“正确”(或者更确切地说,完整、完整)的方式是实现所有状态存储(实现、公开、处理事件、将数据存储在浏览器本地存储或应用程序状态等某处)。正如您所发现的,使用真正的if 切换组件会重置它 - 这就是应用程序状态的来源 - 您将状态保留在用于更改它的事件中,然后在下次组件初始化时,它会读取该状态。但是您必须自己实现这一切,而且工作量很大。

所以,有两个更简单的解决方案:

如您所见,使用 CSS 隐藏旧内容(如果需要),并在同一页面上显示新内容。但是,如果您在某种窗口/对话框中显示它,您可能根本不必隐藏旧内容。

或者,使用某人编写的已内置这些状态功能的组件,以便您可以直接使用它们。 Here 是我所知道的商业广告。

【讨论】:

啊,我的竞争对手 ;) 我想知道使用 Telerik 组件,但我们需要很多不同的功能,此外我想了解细节,所以我制作了非常相似的组件,但不是“页面”它使用一种“无限滚动器” - 因此在用户滚动表格时会预加载内容。还有更多功能,但不是状态管理 ;) 披露:我为 Telerik 工作。也就是说,网格具有无限(虚拟)滚动和大量其他功能 :) 就是说,我确实认为你正在做的事情可以工作,至少现在是这样。如果您开始在其他页面或用户会话之间开始需要该状态,则必须全力以赴并实现实际的组件和/或应用程序状态。 好吧,我的省力解决方案似乎效果不佳。它通过了我的测试,但客户声称应用程序开始变慢,然后在使用几个小时后崩溃。内存泄漏?而这一切仅仅是因为不同记录的呈现表单之间没有页面切换? 在其他地方可能存在泄漏,不一定是在 UI 部分,数据服务缓存内容并且从不释放它对我来说听起来更有可能。如果您的自定义网格组件涉及到它,它也可能会泄漏,特别是如果某些资源清理没有在 Dispose 上发生(例如清除 refs 和 js 互操作处理程序) 好吧,表格仍然存在,所以它不是问题的根源。但另一方面的表格 - 它们位于剃刀文件的条件部分。所以它们被摧毁和创造。是的,他们使用 JS 互操作——我从来没有读过它应该被处理掉。有没有关于那个地方的文档?我从未在 Blazor 示例中见过 IDisposable,所以我认为只有在内部使用一些非 Blazor 一次性用品时才应该实现 IDisposable。

以上是关于Blazor:如何存储页面状态(所有组件状态)?的主要内容,如果未能解决你的问题,请参考以下文章

Blazor 服务器端 SPA:重新加载组件后的组件状态

如何在服务器端 Blazor 中存储会话数据

服务器端 Blazor:刷新页面后如何保持用户身份验证?

从 Blazor 组件 (.razor) 重定向到 Razor 页面 (.cshtml) [服务器端]

React + Redux + Router - 我应该为所有页面/组件使用一个状态/存储吗?

如何制作 Blazor 页面互斥锁