我如何在本机聊天应用程序中使用 GraphQl 订阅来从 GraphQl 查询中获取实时更新

How can i use GraphQl subscriptions in react-native chat application to get real-time updates from GraphQl queries

我在 react-native 聊天应用程序中使用 GraphQl APIs。我想在另一个用户向我发送消息而不刷新 API 时获得实时更新。我如何使用 GraphQl API 在 react-native 中使用 GraphQl 订阅或 Websocket 来做到这一点?

我应该使用不同的 URL 进行订阅和正常的 API 吗?

这是我的config.js

import { ApolloClient } from 'apollo-client';
import { createHttpLink } from 'apollo-link-http';
import { WebSocketLink } from 'apollo-link-ws';
import { HttpLink } from 'apollo-boost';
import { setContext } from 'apollo-link-context';
import { InMemoryCache } from 'apollo-cache-inmemory';
import { AsyncStorage } from 'react-native';

// const httpLink = createHttpLink({
//     uri: 'https://graphql.chat.dev.com/graphql',
// });

// const link = new HttpLink({
//    uri: `https://graphql.chat.dev.com/graphql`,
//    headers: {
//      Authorization: AsyncStorage.getItem('@user_token');
//    }
//  });

 const link = new WebSocketLink({
  uri: `wss://graphql.chat.dev.com/graphql`,
  options: {
    reconnect: true,
    connectionParams: {
      headers: {
        Authorization: AsyncStorage.getItem('@user_token');
      }
    }
  }
})

const defaultOptions = {
  query: {
    fetchPolicy: "network-only",
    errorPolicy: "all"
  }
};

const client = new ApolloClient({
    link: link,
    cache: new InMemoryCache(),
    defaultOptions
});

export default client;

我没有用 React Native 实现 Apollo,但我用我的 React 应用实现了它。根据我的经验,您应该为订阅 API 和普通 API 使用不同的 URL。然后,用import { split } from 'apollo-link'拆分links,这样就可以给每个link发送数据了 取决于发送的操作类型。您可以在 Apollo here 中阅读有关订阅的更多信息。
这是我的 client.js 文件。希望对你有帮助。

import { ApolloClient } from 'apollo-client'
import { createUploadLink } from 'apollo-upload-client'
import { InMemoryCache } from 'apollo-cache-inmemory'
import { setContext } from 'apollo-link-context'
import { split } from 'apollo-link'
import { WebSocketLink } from 'apollo-link-ws'
import { getMainDefinition } from 'apollo-utilities'

const getToken = () => localStorage.getItem('AUTH_TOKEN')
const APOLLO_SERVER ="APOLLO_SERVER url"
const APOLLO_SOCKET ="APOLLO_SOCKET url"

// Create an http link:
const httpLink = createUploadLink({
 uri: APOLLO_SERVER,
 credentials: 'same-origin',
})

const authLink = setContext((_, { headers }) => {
 const token = getToken()
 return {
  headers: {
   ...headers,
   authorization: token ? `Bearer ${token}` : '',
  },
 }
})

// Create a WebSocket link:
const wsLink = new WebSocketLink({
 uri: APOLLO_SOCKET,
 options: {
  reconnect: true,
  connectionParams: {
   Authorization: getToken() ? `Bearer ${getToken()}` : '',
  },
 },
})

// using the ability to split links, you can send data to each link
// depending on what kind of operation is being sent
const link = split(
 // split based on operation type
 ({ query }) => {
  const definition = getMainDefinition(query)
  return (
   definition.kind === 'OperationDefinition' &&
   definition.operation === 'subscription'
  )
 },
 wsLink,
 authLink.concat(httpLink)
)

const cache = new InMemoryCache()

const client = new ApolloClient({
 cache,
 link,
 typeDefs,
 resolvers,
})

这是我将查询与订阅集成在一起的组件:

import React, { useEffect } from 'react'
import { useQuery } from '@apollo/react-hooks'
import gql from 'graphql-tag'
...

// query for querying message list
const GET_MESSAGE_LIST = gql`...`
// subscription for listening new message
const ON_MESSAGE_CREATED = gql`...`

const ChatView = props => {
  const { data, loading, subscribeToMore } = useQuery(GET_MESSAGE_LIST, {
    {
   notifyOnNetworkStatusChange: true,
   variables: {
    query: {
     limit: 10,
     userId: props.userId,
    },
   },
  }
  })
  
  useEffect(() => {
    subscribeToMore({
   document: ON_MESSAGE_CREATED,
   variables: {  filter: { userId: props.userId }  },
   shouldResubscribe: true,
   updateQuery: (prev, { subscriptionData }) => {
    let newMessage = subscriptionData.data.onZaloMessageCreated
    
    return Object.assign({}, prev, {
     messageList: {
      ...prev.messageList,
      items:
       prev.messageList.items.filter(
        item => item.id === newMessage.id
       ).length === 0
        ? [newMessage, ...prev.messageList.items]
        : prev.messageList.items,
     },
    })
   },
  })
  }, [subscribeToMore])
  
  return ...
}