布莱恩F爱
从专注于角图,Web技术以yobet英雄联盟及波特兰的Node.js的Google开发人员专家中学习。
广告 ·ultimatecourses.com.
用终极课程学习角度正确的方式

角转移状态

了解如何使用通用有效地使用服务器和静态渲染进行角度传输状态。

什么?

角的转浮盐类使服务器端呈现(SSR)和PreRendered(SSR)角度应用程序可以在浏览器中使用来自服务器获取的数据有效地呈现。yobet外围让我们突破一个,从潜在的问题开始。

的问题

如果您使用的是SSR或PreRendered应用程序策略,则该过程大致如此:

  1. prerender或在服务器上呈现应用程序
  2. 浏览器获取呈现的HTML和CSS并显示“静态”应用程序
  3. 浏览器获取、解析、解释和执行JavaScript
  4. Angular应用被引导,用新的“正在运行”的应用替换整个DOM树
  5. 应用程序被初始化,通常从远程服务器或API获取数据
  6. 用户与应用程序交互

在这个场景中有两个问题:

  1. DOM水化目前正在替换整个节点树并重新绘制应用程序
  2. 应用程序正在获取理论上已经拥有的数据,并且由于SSR或预呈现站点策略而显示给用户的数据

第一个问题目前在Angular中还没有解决,坦率地说,这是一个复杂的挑战。然而,第二个问题目前已经在Angular(截至本文撰写时的版本9)中解决了转浮盐

是什么转浮盐吗?

传输状态是一种策略,其中我们:

  1. 使用SSR或预呈现策略获取呈现完整“静态”应用程序所需的数据
  2. 序列化数据,并使用初始文档(HTML)响应发送数据
  3. 在初始化应用程序时,在运行时解析序列化数据,避免了数据的冗余获取

从技术上讲,数据通过序列化json.stringify()并通过json.parse()。但是,通常我们不需要担心这个问题,因为这是由转浮盐服务在棱角。

让我们快速回顾一下文档:

商店中的值使用json.stringify / json.parse序列化/次序列化。所以只有布尔,数字,字符串,空和非类对象都将以非损耗方式序列化和解除序列化。

如果您的应用程序需要将状态从服务器传输到不符合这些要求的客户端,那么您将需要实现用于将数据转换为以及来自我所谓的“兼容”数据的策略。

我的特定用例是包含包含的FireStore的对象DocumentReference类。文档引用是Firestore中的外键,这是Firebase SDK提供的一个特殊类。

目标

我使用转移状态的目标是:

  1. 利用RXJS数据流使用SSR或PRERENTERS“拦截”获取数据
  2. 实现一种策略,将不兼容的数据转换为兼容的数据以进行序列化,并反过来将序列化的兼容数据转换回原始结构

第三个目标对于我的用例来说是必要的,因为我需要转换Firestore的DocumentReference课程进入可以序列化的东西转浮盐

开始

来开始转浮盐我们需要的服务:

  1. 导入servertransferstateModule.在服务器应用程序模块中。
  2. 导入browsertransferstateModule.在我们的浏览器应用程序模块中。

当使用服务器端渲染时,您通常会有一个单独的应用程序入口点,最常见的是a的形式src / main.server.ts文件。并且,浏览器入口点最常见src / main.ts由角CLI生成的文件。然后这些文件将通过a引导应用程序ngmodule.类。

所以,让我们先开放src / app / app.server.module.ts并导入servertransferstateModule.:

@ngmodule.({进口:(appmodule.,ServerModule,servertransferstateModule.],引导:(AppComponent.],})出口AppServerModule{}

然后,我们导入browsertransferstateModule.src / app / app.module.ts文件:

@ngmodule.({宣言:(AppComponent.],进口:(浏览器withservertransition.({appId:“serverApp”}),browsertransferstateModule.,CoreModule,/ /代码省略],引导:(AppComponent.],})出口appmodule.{}

TransferStateService

要解决拦截rxjs流中的获取数据的第一个目标我创建了一个TransferStateService它可以提供给Angular的组件类来获取数据。

@可注射的({providedIn:“根”,})出口TransferStateService{/** *状态密钥。* /私人钥匙=地图<字符串,StateKey<字符串>>();构造函数(@注入(PLATFORM_ID)私人只读的platformId,私人只读的transferState:转浮盐){}<T>(关键:字符串,observableInput:可观测的<T>,defaultValue吗?:T,转换器吗?:TransferStateConverter<T>):可观测的<T>{如果((关键)){返回(得到(关键,defaultValue,转换器))(龙头(()=>删除(关键)));}返回observableInput(龙头(()=>(关键,,转换器)));}得到<T>(关键:字符串,defaultValue吗?:T|空值,转换器吗?:TransferStateConverter<T>):T|空值{如果(!(关键)){返回defaultValue||空值;}常量=transferState得到<T>(getstatekey.(关键),defaultValue);返回转换器吗?转换器fromTransferState():;}(关键:字符串):布尔基{返回transferStatehasKey(getstatekey.(关键));}删除(关键:字符串):空虚{如果(!(关键)){返回;}transferState删除(getstatekey.(关键));}<T>(关键:字符串,:T,转换器吗?:TransferStateConverter<T>):空虚{如果(isPlatformServer(platformId)){如果((关键)){安慰警告(使用键将现有值设置为TransferState:$ {关键});}如果(!环境生产){安慰日志(存储TransferState为:'$ {关键});}transferState(getstatekey.(关键),转换器吗?转换器totransferstate():);}}私人getstatekey.(关键:字符串):StateKey<字符串>{如果(钥匙(关键)){返回钥匙得到(关键);}钥匙(关键,makestatekey.(关键));返回钥匙得到(关键);}}

让我们快速回顾:

  • 首先,我们注射了platformId字符串和转浮盐类实例。我们将使用platformId来检查我们是否在服务器的上下文中执行Angular应用程序。如果您使用的是基于浏览器的预呈现策略,那么您需要调整它,以确定应用程序何时在预呈现上下文中执行。
  • 然后,我们定义了a方法接受关键唯一标识数据的值,observableInput和可选的defaultValue转换器。我们将更多地讨论下面的转换策略。
  • 方法“拦截”下一个通知,并使用转浮盐服务。的类中的方法处理此操作。
  • 得到方法返回值转浮盐如果存在,则返回defaultValue要么空值。它还处理从“兼容的”序列化值到原始值的数据转换。
  • 方法返回A.布尔基值,该值指示数据是否存在于转浮盐类。
  • 删除方法中删除数据转浮盐类。这是为了确保后续下一个客户端的RXJ可观察流中的通知不是在服务器端上获取的陈旧数据。
  • 方法将数据存储到转浮盐服务,以及将不兼容的数据转换为可序列化的值。
  • 最后,私人getstatekey.方法返回StateKey为了关键字符串提供。

这是使用使用的样本实现TransferStateService在Angular的解析器中:

出口Ruleresolver实现了解决<规则>{构造函数(私人只读的rulesService:RulesService,私人只读的transferStateService:TransferStateService){}解决(快照:ActivatedRouteSnapshot){返回transferStateService<规则>(规则,rulesServicegetbyslug.(快照paramMap得到(“鼻涕虫”)));}}

上面我们用注入的方法TransferStateService实例来存储在RuleService.getBySlug ()方法。

TransferStateConverter

正如我之前在我的特定用例中提到的那样,我有需要将序列化转换为序列化的不合规值转浮盐服务。要解决第二个目标,我想创建一个定义的良好和类型安全的实现,用于转换数据。

首先,让我们定义一个新的抽象TransferStateConverter类:

进口{可序列化的}'@ lkt-core /类型';出口抽象TransferStateConverter<T>{/** *由TransferStateService调用,用于将序列化的值转换为t类型的对象抽象fromTransferState(数据:可序列化的<T>):T;/ ** *由TransferstateService调用以将数据转换为由转速序列化的值。* /抽象totransferstate(数据:T):可序列化的<T>;}

转换器必须实现两个必需的方法:

  1. totransferstate方法接受不兼容的数据并返回可序列化的价值。
  2. fromTransferState方法接受可序列化的值,并返回不符合规则的值。

totransferstate方法将在服务器或预呈现的上下文中执行。和,fromTransferState方法将在客户端上的浏览器的上下文中执行。

您还需要定义一个新的可序列化的类型:

出口类型可序列化的<T>=布尔基|数量|字符串|空值|对象|T;

可序列化的类型表示值能够序列化到JSON使用转浮盐服务。

最后,让我们看一个示例实现。我们将继续序列化a规则。在我的应用程序中,这是从Firestore返回的对象,它包含不兼容的对象DocumentReference类。

以下是模型界面的一部分的样子:

出口接口规则{/ /代码省略相关的吗?:阵列<DocumentReference>;标签吗?:阵列<DocumentReference>;}

请注意,相关的标签属性是一个数组DocumentReferenceFirebase SDK提供的类。

让我们创造一个新的Ruleconverter可以委派提供用于转换值的类,从而转换为,以及可序列化的数据:

类型序列化rule.=规则&{相关的吗?:字符串(];标签吗?:字符串(];};@可注射的({providedIn:“根”,})出口Ruleconverter扩展TransferStateConverter<规则>{构造函数(私人只读的rulesService:RulesService,私人只读的tagsService:TagsService){();}fromTransferState(规则:序列化rule.):规则{返回{规则,相关的:规则相关的吗?规则相关的地图((ID:字符串)=>rulesServicegetRef(ID)):(],标签:规则标签吗?规则标签地图((ID:字符串)=>tagsServicegetRef(ID)):(],};}totransferstate(规则:规则):可序列化的<规则>{返回{规则,相关的:规则相关的吗?规则相关的地图((裁判)=>裁判ID):(],标签:规则标签吗?规则标签地图((裁判)=>裁判ID):(],};}}

让我们跳过我的一些具体的实施细节,而且让我们专注于实现的TransferStateConverter摘要课程:

  • 首先,我们扩展TransferStateConverter类,为转换器提供泛型类型。在这种情况下,这个转换器是用来转换a的规则
  • 构造函数()函数为我的实现提供了注入的依赖项。
  • fromTransferState ()方法接受规则参数a序列化rule.并返回一个规则。在我的实现中,我已转换为文档ID,它已经从DocumentReference到A.字符串使用getRef ()在我的服务中的方法。
  • totransferstate()方法接受规则论证,这是不合规规则包含的对象DocumentReference类。此方法转换对此的引用ID字符串值。

我们现在可以将转换器实施到解析器中:

常量规则='规则';出口Ruleresolver实现了解决<规则>{构造函数(私人只读的ruleConverter:Rulesconverter,私人只读的rulesService:RulesService,私人只读的transferStateService:TransferStateService){}解决(快照:ActivatedRouteSnapshot){返回transferStateService(规则,rulesServicegetbyslug.(快照paramMap得到(“鼻涕虫”)),空值,ruleConverter);}}

我喜欢这个做法模式是我提供的Ruleconverter类实例的TransferStateService有效地将值与可序列化的值进行转换,以及将值与可序列化的值进行转换。

结论

我通过定义a实现了我的两个既定目标TransferStateService以及用于定义扩展抽象的类的模式TransferStateConverter类。

布莱恩F爱

嗨,我是布莱恩。我对类型名称,Angular和node.js感兴趣我嫁给了我最好的朋友邦妮,我住在波特兰和我滑雪(很多)。