前言和动机

在这里,在OkC188bet金宝搏官网upid,我们使用的相当大的球迷GraphQL。当谈到对我们的任何客户端平台获取数据,该查询语言提供了抽象授予的灵活性,为我们取恰恰是我们需要在每种情况下的数据。

在一天结束的时候,真的GraphQL仅仅是:一个抽象。突变,查询和订阅类抽象的根本方法,使我们互动与任何数据模型。该模式作为数据的一些源和目的地之间的契约,它定义哪些数据可被查询,以及如何它应该进行查询。这些数据表明输入查询的轮廓将我们GraphQL服务器实例在大多数情况下可以解决,但该数据的目的地(在我们的例子,让我们说这是一个移动应用或作为客户端Web应用程序),并不真正需要了解有关数据的来源和解决策略。

这是非常好的,因为这意味着数据可以来自任何地方的GraphQL服务器可以访问。也许我们需要使用文件系统中的一些东西,或者一个本地数据库,或者一个远程之一来解决我们的数据。或许我们可以称之为暴露给我们一些其他的服务器,通过RPC或REST或任何协议,真的。也许我们的数据是目前在内存的某个地方,这就是技术上的精细以及!我们的数据源(S)的无差异是什么让这个模型和数据图的结构是如此的可扩展性(曼迪智者有一个伟大的视频,演示了这一点的同时覆盖联合图的概念)。

无论数据的来源,在客户端实现并不真的需要在所有的变化,这是关键重要的是要了解使用GraphQL本地状态管理的概念。想象一下,你的应用程序的本地状态:它确实是数据的另一种来源,毕竟,不是吗?那么,接下来的问题是,是什么阻止我们利用此查询语言范式向我们提供的抽象来管理这些数据呢?

怎么运行的

那么,答案是没有什么。如果你是存储在您的应用程序状态的地方,你可以在理论上只是解决GraphQL查询与状态数据,如果你想要的。从实现阿波罗(在我们看来,万物事实上提供商GQL),我们尝试了使用GraphQL指令来表示一个给定的查询块应该以这种方式来解决:@客户

对于什么会看起来像一个例子,假设我们希望有一个应用程序,用户可以将消息发送到彼此。要获得有关谁用户已经接收通知信息,我们可能会进行查询到我们的服务器。然而,也许我们想知道用户当前是否有打开的任何给定的对话的消息窗口。服务器并不真正关心这一块的每个对话信息,但我们的前端应用非常关心它,所以它是一个很大的意义,我们可能再选择店里像这样的客户端状态。假如是这样的话,可以再构建合理的查询数据,当地国家包括在内,就像这样:

查询getAllMessages($用户名:!ID){用户(ID:$用户id){名profilePic消息{ID通讯员{名profilePic} ISOPEN @client}}}

在这个例子中,我们的开了每个用户的邮件标志可以存储在我们的客户端的状态,因为它是没有太大的后端关注。数据的其余部分,但是可以从我们的服务器,并没有别的需要改变牵强。对于一个查询中混用我们的数据源(客户端与服务器)的能力是一个非常有力的想法,并可能导致一些令人难以置信的灵活的单查询。

因为战略为解决这一@客户指令是一个遍历,这意味着该指令可以递归跨越父子及邻居,邻居关系适用于我们的数据,使我们实现了数据图的同样的经历,但与我们的客户状态。我们的客户端状态可以有其父的作品(非客户端状态)结构的直接接入,也可以是一些简单的标量场像布尔标志,或者是更深入和相关结构甚至数据。

客户端的状态并不需要与一些服务器的数据,无论是!它真的可以,我们可能希望保存为客户端状态,就像用户也许对主题偏好,完全前端关注,但事情仍然有状态的当前设置的任何数据。黑暗模式所以在这些日子里,虽然,对不对?

那么,如何做这样的工作?那么,引擎盖下,我们需要配置一些新的作品加入到我们的ApolloClient例如为了使其具有解决客户端查询的战略。要做到这一点,我们明确地阐明了这一点,通过添加一些新的解析器为我们的客户,就像我们会写来解析查询我们的服务器实例。该ApolloClient实例可以同时使用在初始化时,以及在一个特设的基础上添加解析器client.addResolver(someNewResolverToAdd)。阿波罗定义函数签名手柄分辨率像这样,它应该看起来很熟悉,如果你曾经使用过阿波罗服务器以往:

键入ResolverFn =(父:任何,ARGS:任何{缓存}:{缓存:ApolloCache <任何>})=>任何;

忽略父节点和参数的参数,我们可以看到,我们解构属性关闭的对象,被称为高速缓存,就像我们解构一个数据源在属性阿波罗服务器平行于该功能的类型。这是因为在这种情况下,我们的缓存已经采取了数据源的在我们的客户端世界的责任。让我们看一个客户端解析程序安装会是什么样子在这种情况下:

常量defaultResolver = {查询:{用户:{消息:{ISOPEN:(父母,指定参数时,{}缓存)=> {//引用缓存,让您的数据返回cache.readQuery({查询:MESSAGE_IS_OPEN_QUERY,变量:{MESSAGEID:parent.id,}});},},},},};

之后,我们还需要提供一些初始状态的高速缓存也使我们的第一个高速缓存读取才能解决,因此我们需要定义以及和初始化时将其提供给我们的缓存。

//定义初始客户端状态常量defaultState = {用户:{消息:{ISOPEN:假,}}} const的客户=新ApolloClient({//其他阿波罗配置,诸如链路//和高速缓存定义解析器:defaultResolver,});//总理与初始状态client.writeData缓存({查询:MESSAGE_IS_OPEN_QUERY,数据:{defaultState,}})

在这个例子中,我们只是设置默认状态给定消息

了阿波罗的直觉是,不仅提供该指令和选项来解决查询在客户端,而是提供了客户端缓存,大多数ApolloClient实例无论如何定义(这通常是用来存储响应我们的查询,实际上做的解析服务器上),以存储此客户端状态的位置。这使得有很大的意义,我们有一个当地的商店(我们的ApolloClient的高速缓存),我们有办法与存储(使用GQL交互的)......这是,在本质上,是什么样的解决方案终极版(我敢肯定,不需要介绍在这一点上)或MobX为我们提供了对不对?

嗯,是。这工作完全正常,太!当我们探讨过这个作为一个选项然而,我们注意到了一些东西,最终导致我们做出不依赖于阿波罗状态管理的决定。

我们遇到的问题

那么,为什么我们决定不实施这个呢?那么,决定背后的原因肯定是具体到我们的场景,也许不会像别人重要,但确实包含了一些见解,我觉得会考虑,任何人都下去了阿波罗路径将不得不权衡为好。

开发人员开销和学习曲线

虽然这可以作为一个阶段的管理解决方案,它带有一些新的开销。一个现在必须写自己的客户端状态解析器,虽然这是为案例任何状态管理选项,它并不像它看起来似乎很简单。

要真正正确地写这些解析器,你会想在直接与高速缓存工作的一些经验/资质。随着3.0版本,阿波罗/客户端已经有一些相当激烈的更新缓存程序如何处理标准化和非标准化的数据。了解如何使用缓存IDS和__typenameS,决定是否合并或替换数据,并学习如何做等等都是意料之中的这种范式的过程。旁注,方大同@阿波罗刚刚公布一个令人难以置信的博客文章进入有关阿波罗缓存和理解缓存正常化深度。这给了我们的两个选项为我们的缓存数据:要么确保每个查询请求我们正在请求数据的唯一标识字段(不这场失利请求任何字段,我们要的目的是什么?)或书面形式明确typePolicies告诉我们缓存如何规范我们的数据。从一个人写一个有众多不同的使用情况正常运行客户端库的角度来看,我理解这样一个解决方案的动机。然而,这仅仅是不是通过像终极版的解决方案与客户端状态的问题。

对比反对这样的范例反应过来的上下文API与串联useReducer钩,甚至是终极版的建筑,好像阿波罗解决方案更了解和从开发人员的角度来管理。对于权衡,不过,我们也获得思考的能力和与相互作用我们所有的应用程序的数据以相同的方式,这无疑是一个真棒益处。但是这值得吗?

新的东西,借来的东西?

好了,我们已经与终极版工作在这里雷霆,而在旧的代码一些例子,甚至是反流性食管。添加在我们的应用程序状态管理一个新的选择真的会导致一个混乱的烂摊子,将毫无疑问是复杂的人谁是入职到我们的团队在第一环绕他们的头。就个人而言,我觉得开发商的经验和可维护性应该是巨大定义任何建筑或框架决定的因素。

在“终极版已死”的说法已经提出了许多次,与此相关的传统成本是进来的形式样板和包装组件可以很容易地认为不很可扩展性,一有成气候之前更改文件的屈指可数。尽管如此,虽然,它肯定已经成熟了多年。如果使用得当,绝对可以成为一件轻而易举的工作和它显然也有一些后劲(更不用提,与终极版工作挂钩实际上是非常好的)。更何况,剥开我们现有的架构将需要几个月的时间,并增加另一个范例学习和遵循沿着现有的状态管理范式将导致更多的情况下,当开发者编写的代码转换,并有可能只是混淆视听,负担他们。

最重要的是,也有可供自己支配的资源无数,使用和理解终极版(或任何成熟的OSS,对于这个问题),一两件事,我当然有问题,与个人研究阿波罗客户端状态管理时;那里只是没有尽可能多的文件,影片,并在阿波罗方法的文章,或许是因为相比于类似Redux的时候是比较模糊或在其生命的早期。此外,一个更成熟的解决方案可能会提供定义为开发者工作,稳定的API的条款更多的价值,而一个年轻的一个可能是在这方面更加动荡(这是所有非常态势,不过,我会承认)。

然而,有“变了这么多文件”和“它被过于复杂”的对抗终极版普遍的说法并没有真正似乎对阿波罗的解决办法补救。还是要理智colocate解析器和初始状态的定义,并且成就了这样的事情我以后,我觉得我只是写样板一些终极版这感觉相当讽刺我。与缓存直接工作似乎并没有那么复杂我比店里打工,要么。

阿波罗也有一个开发工具,提供为好,这是我用很喜欢,发现是有用的,但它也认为,当一次反像终极版的平行一点点不成熟的。有时,它并不想发动。它不提供有趣的功能,如时间旅行,并有一两件事我很兴奋,使用它,这是客户端的反省,将需要确定类型定义ApolloClient实例(这基本上是创造我们的客户端的状态,这是真正的另一个一整套的事情担心和管理模式的过程,但我得承认,也许打字稿或代码生成可以在这个场景真的亮)。在我使用其他库,没有必要确定我们的客户端状态多次的形状,如果有的话,它的开始看起来像这种情况正在开始积累一些阿波罗端样板。

其他选项

我们也一直在尝试作出反应的语境API,想必将要考虑在未来一些其他的选择也是如此。然而,我们选择对我们的集束大小影响什么的考虑是美国超级重要。难道上下文/阿波罗删除一个状态管理完全依赖的需要?对于一些简单的应用,我认为有例子在那里,其中上下文已被证明是绰绰有余。同样,也有是绰绰有余以及阿波罗的解决方案的一些例子!还有MobX,Facebook的新的开源产品畏缩,甚至建模使用状态机与您的客户端状态XSTATE

我们在哪里扣除了呢?

这是很难不承认不可思议的工作,阿波罗已经完成。阿波罗和GraphQL有清理我们的API和我们的客户的通用网络层完成的奇迹。追求它作为国家管理的一个选项,但是,对我们的代码库产生重大影响,而在这个时候,我们只是不觉得争论是给阿波罗的客户端状态管理的成熟度和我们的客户的当前设置引人注目的足够侧的状态。该回报率的投资实现的代码库新的东西有很多现有的架构的需要相对高的在我看来。我只是不知道,与阿波罗投资回报率足够高在这种情况下。

一些新的见解武装在探索阿波罗的提供更多一些,不过,我们会希望能够得出更好的结论,最终对我们应该依靠什么来解决这个问题,我们应该如何看待的做法,架构后,和任何库,框架或工具的权衡,我们决定用卷。在此之前,我们将继续我们的眼睛一直就如何阿波罗的客户端状态的解决方案的演进。