AWS使用TypeScript和Hook扩展GraphQL操作 – 第4部分 [Subscriptions]

接下来是订阅。这是GraphQL和AppSync的一个有趣功能。利用实时数据的能力确实可以为你的应用带来一些不错的用户体验。我倾向于谨慎使用它,但它对小列表和即时反馈非常有帮助。

我们以前的帖子已经构建了一组相当不错的抽象,我们也可以在这里使用它们。因此,我将在此时开始粘贴结果并将其分解成碎片。拿一杯咖啡,我们就可以了。

编码

这是我们完成的自定义钩子:

推荐阅读
2

如何在Microsoft Azure云中拍摄磁盘快照

1的1,819
type ConfigType<VariableType extends {}> = {   query: string;   key: string;   variables?: VariableType; };  export const useSubscriptionByItself = <   ItemType extends { id: string },   VariablesType extends {} = {} >({   config,   itemData, }: {   config?: ConfigType<VariablesType>;   itemData?: ItemType; } = {}) => {   const (item, update) = React.useState<ItemType | undefined>(itemData);    React.useEffect(() => {     let unsubscribe;     if (config) {       const { query, key, variables } = config;       const subscription = API.graphql(graphqlOperation(query, variables));       if (subscription instanceof Observable) {         const sub = subscription.subscribe({           next: payload => {             try {               const {                 value: {                   data: { (key): item },                 },               }: {                 value: { data: { (key: string): ItemType } };               } = payload;                update(item);             } catch (error) {               console.error(                 `${error.message} - Check the key property: the current value is ${key}`               );             }           },         });         unsubscribe = () => {           sub.unsubscribe();         };       }     }     return unsubscribe;   }, (JSON.stringify(config)));    return (item); }; 

这里有很多,但我们的用例很简单。我们的订阅将处理一个项目。这可能就像订阅创建的新博客一样简单,例如:

const (item) = useSubscription<postFragment>({   config: {     key: 'onCreatePost',     query: onCreatePost,   }, }); 

我们还可以在更新时传递一些变量来订阅注释:

const (comment) = useSubscriptionByItself<   commentFragment,   onUpdateCommentSubscriptionVariables >({   itemData: comment,   config: {     key: 'onUpdateComment',     query: onUpdateComment,     variables: {       id,     },   }, }); 

关键是我们能够采用的样板 const subscription = API.graphql(graphqlOperation(query, variables)); 并将其提取为可以重复使用的东西,以及倾向于AWS Amplify如何以强类型方式返回数据来处理所有内容的惯例。

让我们从顶部开始,看看发生了什么。

输入配置

type ConfigType<VariableType extends {}> = {   query: string;   key: string;   variables?: VariableType; };  export const useSubscription = <   ItemType extends { id: string },   VariablesType extends {} = {} >({   config,   itemData, }: {   config?: ConfigType<VariablesType>;   itemData?: ItemType; } = {}) => { 

我们来看一下类型参数(尖括号之间的东西)。这需要一些解释,因为我开始假设一个约定。该 ItemType 表示我们将在钩子中返回并操作的对象。该 extends { id: string } 意味着无论我们传入什么对象,它都必须具有类型的id string 作为财产。这很有用,因为我们想要一个对象的唯一标识符。该 itemData 用于我们想要初始化我们的状态的情况。

请注意,我正在利用片段来提供我们可以使用的单个类型对象。一旦创建,放大 codegen 工具将为你的片段创建类型,然后你可以像我们在此示例中那样使用它们。你可以在此处了解有关片段以及如何在GraphQL中使用它们的更多信息。

第二 VariableType 将成为一个对象,表示我们将传递给我们的订阅的任何变量 graphqlOperation。这在下面的类型声明中进一步使用 ConfigType。这表示保留订阅的配置 queryvariableskey 我们将用它来建立我们的订阅。我们会回来的 key 稍后。

国家

const (item, update) = React.useState<ItemType | undefined>(itemData); 

这非常简单。我们用的是 ItemType 我们传入的参数键入 useState 功能。这可能是未定义的,所以我们也注意到了。如果我们最初通过 itemData,我们也使用它来建立将跟踪我们正在使用的订阅的状态。

效果

这是真正的肉。

React.useEffect(() => {   let unsubscribe;   if (config) {     const { query, key, variables } = config;     const subscription = API.graphql(graphqlOperation(query, variables));     if (subscription instanceof Observable) {       const sub = subscription.subscribe({         next: payload => {           try {             const {               value: {                 data: { (key): item },               },             }: {               value: { data: { (key: string): ItemType } };             } = payload;              update(item);           } catch (error) {             console.error(               `${error.message} - Check the key property: the current value is ${key}`             );           }         },       });       unsubscribe = () => {         sub.unsubscribe();       };     }   }   return unsubscribe; }, (JSON.stringify(config))); 

首先,我们将建立一个订阅,所以为了效果,我们需要在完成后清理它。我们声明一个变量,它将保存从效果返回时要运行的函数。

接下来,我们将检查配置是否存在,因为它是可选的。我们对组件进行解构,并使用它们来构建我们的订阅。下一行很重要:

  const subscription = API.graphql(graphqlOperation(query, variables));   if (subscription instanceof Observable) {     ... 

API.graphql 呼叫实际上返回 Observable | Promise<> – 这意味着结果将是一个或另一个。为了获得我们期望的自动完成帮助(并阻止TypeScript对我们大喊大叫),我们需要使用类型保护来执行所谓的“类型缩小”。我们这样做是通过使用 instanceof 用于检查类型是否为的关键字 Observable。我添加了 @types/zen-observable 包(yarn add -D @types/zen-observable)提供类型。

订阅

const sub = subscription.subscribe({   next: payload => {     try {       const {         value: {           data: { (key): item },         },       }: {         value: { data: { (key: string): ItemType } };       } = payload;        update(item);     } catch (error) {       console.error(         `${error.message} - Check the key property: the current value is ${key}`       );     }   }, }); unsubscribe = () => {   sub.unsubscribe(); }; 

我们的订阅是从graphql调用返回的,所以现在我们需要订阅它。这是使用所谓的可观察的。上次我检查时,Amplify使用zen-observable库进行订阅实现。 Observable通过将它们作为流返回来操作值,因此你可以通过提供回调来监听流的更新 – 在这种情况下, next。我们的 next 回调需要一个 payload (这将是流中下一个事件的值)然后我们对此值进行一些解构以获取我们想要的基础数据。 Amplify遵循在订阅中返回数据的约定,因此我们可以使用它来确保我们的解构是正确的。

const {   value: {     data: { (key): item },   }, }: {   value: { data: { (key: string): ItemType } }; } = payload; 

我们用的是 key 我们之前谈过,以及 ItemType 我们传入的类型,从嵌套对象创建一个类型和正确的解构(以。的形式) value.data(key))。处理完这些数据后,我们就会使用 update 来自我们的方法 useState 挂钩以保持我们的状态,如果出现任何问题,我们会注销错误。

回调后,我们为我们分配一个小箭头函数 unsubscribe 如果卸载了使用挂钩的组件,则该变量将执行取消订阅的工作。

(JSON.stringify(config)); 

我们的 useEffect hook接受一个依赖项(一个对象),所以我们只是 stringify 它确保如果它以任何方式改变,我们的钩子将再次运行,我们可以重新建立适当的订阅。

最后一行只返回保持状态的数据,因此我们可以从调用者中使用它。

return (item); 

点评

从本质上讲,这只是现有Amplify工具的一个盘点器。但对于TypeScript项目,它可以为你提供帮助,以确保你的应用程序正在按预期执行。在我看来,不错的副产品是API表面更完整,同时抽象掉了公共位。提取这些东西并避免使用它通常是一种很好的做法 useEffect 直接在你的组件中。这只是朝这个方向迈出的一小步。

如果有人对此方法有任何反馈,请将其留在评测中。我经常使用它,只在TypeScript项目中,我希望它可以帮助某人。你也可以在twitter @mwarger上ping我。

但是等等,如果你需要订阅许多活动怎么办?那是下一个 – 跟着我发布时得到通知

资讯来源:由0x资讯编译自DEV,原文:https://dev.to/mwarger/aws-amplify-graphql-operations-with-typescript-and-hooks-part-4-subscriptions-h0j ,版权归作者所有,未经许可,不得转载
关注我们:Twitter | Facebook | Linkedin | Medium | Telegram | Weibo | WeChat