带有 GraphQL Apollo 客户端的订阅组件

Posted

技术标签:

【中文标题】带有 GraphQL Apollo 客户端的订阅组件【英文标题】:Subscription component with GraphQL Apollo Client 【发布时间】:2019-01-18 12:59:43 【问题描述】:

我有一个订阅的应用程序已经在使用 subscribeToMore

查询组件

<Query query=GET_MESSAGES>
  ( data, subscribeToMore ) => 
    return (
      <MessageList
        messages=data.allMessages
        subscribeToMore=subscribeToMore/>
    );
  
</Query>

该查询加载了一个消息列表,据我所知,我们将订阅者附加到 ComponentDidMount 中,因此每当我在查询内的列表中添加新元素时,我的订阅将监听订阅并执行我想要的任何操作(在这种情况下,将新消息添加到我当前的消息列表中)。

消息组件列表:

export default class MessageList extends React.Component 
componentDidMount() 
  this.props.subscribeToMore(
    document: MESSAGE_CREATED,
    updateQuery: (prev,  subscriptionData ) => 
      if (!subscriptionData.data) return prev;
      return 
        allMessages: [
          subscriptionData.data.messageCreated,
          ...prev.allMessages
        ],
      ;
    ,
  );


render() 
  return (
    <div>
      this.props.messages.map(message => (
        <MessageElement key=message.id 
                        message=message/>
      ))
    </div>
  );

我想添加另一个订阅,所以如果我编辑我的消息,信息会实时更新。为了实现这一点,我使用 Subscription

创建了以下组件

消息组件(我想根据更新的消息添加另一个订阅)

export default class MessageElement extends Component

componentDidMount() 
    this.messageUpdatedSubscription();



messageUpdatedSubscription = () => (
    <Subscription
      subscription=MESSAGE_UPDATED>
      ( data:  messageUpdated  ) => (
        console.log('Do smthg???',messageUpdated)
      )
    </Subscription>
  );


render()
    return(
        <Mutation mutation=UPDATE_MESSAGE key=this.props.message.id>
         updateMessage => (
            <div>
                <div>this.props.message.text</div> 
                <div>
                    <Star active=this.props.message.isFavorite 
                         onClick=() =>  updateMessage( variables:  
                                          id: this.props.message.id, 
                                          text:this.props.message.text,
                                          isFavorite:!this.props.message.isFavorite  );
                    />
                </div>
            </div>
          )
       </Mutation>);

我在服务器上的订阅正在工作,因为我已经在 Query 上订阅了 MESSAGE_CREATED,并且我已经在服务器上测试了我对 MESSAGE_UPDATED 的订阅已被触发。但是,我无法弄清楚为什么 UI 没有显示或 console.log 任何内容,就好像它没有收听订阅一样。

我可以通过订阅组件或 subscribeToMore 来实现吗?

提前致谢

【问题讨论】:

【参考方案1】:

无法在 ComponentDidMount 中启动订阅组件。它必须驻留在 render() 生命周期方法中。它的参数可以在 ComponentDidMount 中使用,但不能在组件中使用。

我能想到 3 种可能的解决方案:

1) 您可以尝试将 Subscription 方法放入您的渲染方法中。您只需要将它嵌套在 Mutation 组件的内部或外部。

2) 您可以在该组件的父组件中启动订阅组件,并将其参数(messageUpdate)向下传递给组件 MessageElement。然后,您可以在 ComponentDidMount 中使用 props 的 messageUpdate。

3) 你可以使用 Apollo 的高阶组件。然后你可以在 props 中访问 messageUpdate。 (免责声明 - 我之前没有尝试过)。

我希望这会有所帮助!

【讨论】:

谢谢@cory-mcaboy。我最终通过将我的订阅嵌套到我的突变中来解决您的第一个建议。【参考方案2】:

根据@cory-mcaboy 的建议,我将订阅嵌套到突变中。 我还发现,因为我有一个消息列表,我只想根据我正在更新的消息而不是整个列表来触发订阅;我必须通过以下方式在后端和前端修改我的订阅:

服务器架构

const typeDefs = gql` type Subscription 
                      messageUpdated(id: Int!): Message`;

服务器解析器

 Subscription: 
    messageUpdated: 
        subscribe: withFilter(
                   () => pubsub.asyncIterator([MESSAGE_UPDATED]),
                         (payload, variables) => 
                         return payload.messageUpdated.id === variables.id;
                                        ,
                   ),
      ,

客户端组件

const MESSAGE_UPDATED = gql` subscription messageUpdated($id: Int!)
            messageUpdated(id:$id)
             
                id
                text
                isFavorite
            `;

export default class MessageElement extends Component
render()
    return(<Mutation mutation=UPDATE_MESSAGE key=this.props.message.id>
            updateMessage => (
                <div>
                    <div>this.props.message.text</div> 
                     <Subscription subscription=MESSAGE_UPDATED
                                   variables= id: this.props.message.id >
                        () => 
                            return <Star active=this.props.message.isFavorite 
                                        onClick=() =>  updateMessage( variables:  
                                                                        id: this.props.message.id, 
                                                                        text: this.props.message.text,
                                                                        isFavorite: !this.props.message.isFavorite  );/>
                        
                    </Subscription>
                </div>
            )
        </Mutation>
    );

您可以在以下repo中看到代码:后端itr-apollo-server,前端itr-apollo-client

【讨论】:

以上是关于带有 GraphQL Apollo 客户端的订阅组件的主要内容,如果未能解决你的问题,请参考以下文章

使用带有 React 和 Apollo 的 graphql 订阅制作实时应用程序

Rails、Graphql、Apollo 客户端的 Auth Token 无效

未处理的 GraphQL 订阅错误

带有 Vertx 订阅的 Apollo GraphQL 失败

使用带有 Kotlin 和流的 Android 上的 Apollo 订阅 GraphQL 时处理网络错误

AWS 云中带有订阅的 Apollo GraphQL 服务器