2

我需要一些帮助来弄清楚订阅和实时更新的一般方法是什么。我有一个 React Native 应用程序并使用 Apollo 和 Graphcool 服务作为后端。

在某些情况下,查看应用程序的用户会收到推送通知,说明发生了一些变化。自然,屏幕数据也应该得到更新。订阅是该工作的明显候选人,我基本上得到了它的工作。

我有一个这样的订阅,它本身就可以正常工作(用于在谷歌地图上定位玩家头像)。

subscription PlayerMap($gameId: ID) {
  Game(filter: { mutation_in: [CREATED, UPDATED], node: { id: $gameId } }) {
    node {
      players {
        id
        character {
          id
          name
        }
        user {
          id
          latitude
          longitude
        }
      }
    }
  }
}

然后有一个不同的应用程序屏幕执行突变createPlayer以及refetchQueries来自 Apollo(为简单起见)运行此查询以更新内容。

query GameCharacters($gameId: ID!) {
  Game(id: $gameId) {
    players {
      id
      character {
        id
        name
      }
    }
  }
}

现在完成后,订阅查询(在另一个屏幕上仍处于活动状态)也会更新,但由于某种原因,对象Game中缺少整个节点。data

为了处理订阅,我有一个这样的组件。

class Subscriber extends Component<void, Props, void> {
  componentDidMount() {
    this.subscribe()
  }
  componentWillReceiveProps({ data, shouldResubscribe }) {
    if (this.unsubscribe) {
      if (shouldResubscribe && shouldResubscribe(data, this.props.data) !== true) {
        return
      }
      this.unsubscribe()
    }
    this.subscribe()
  }
  subscribe() {
    const { data, query, variables } = this.props
    this.unsubscribe = data.subscribeToMore({
      document: query,
      variables,
    })
  }
  unsubscribe: ?Function = null
  render() {
    return this.props.children(this.props.data)
  }
}

然后我可以像这样简单地将它与渲染道具模式一起使用。

const OrgMapScreen = ({ gameId, data: initialData }: Props) => (
  <Subscriber
    data={initialData}
    query={OrgMapSubscription}
    variables={{ gameId }}
    shouldResubscribe={(nextData, prevData) => nextData.Game !== prevData.Game}
  >
    {({ Game }) => {
      const markers = Game.players.map(makePlayerMarker)
      return <MapScreen mapProps={{ markers }} />
    }}
  </Subscriber>
)

我很困惑为什么会这样。有一些推荐的方法来处理这样的事情吗?也许refetchQueries我也应该设置另一个订阅而GameCharacters不是?

4

1 回答 1

2

如果我不得不猜测(不是 Apollo 专家),我猜这与您的错误document输入有关subscribeToMore(似乎您使用的是查询而不是订阅作为参数?)或缺少updateQuery,subscribeToMore它返回更新的数据。

在我们的例子中,我们有一个orderChanged订阅来监听Order. 当我们收到更新时,我们希望将orders查询中的订单替换为更新后的订单。我们在updateQuery函数中这样做subscribeToMore(对错别字表示歉意,这不是精确的复制粘贴):

componentDidMount() {
  this.props.data.subscribeToMore({
    document: OrderSubscription,
    variables: {
      range: [0, 25]
    },
    updateQuery: (prev, { subscriptionData, }) => {
      // If no subscription data is passed, just return the previous
      // result from the initial `orders` query
      if (!subscriptionData.data) return prev

      // get the data for the updated order from the subscription 
      const updatedOrder = subscriptionData.data.orderChanged

      // find the index of the updated order from within the existing 
      // array of orders from the `orders` query
      const existingOrderIndex = prev.orders.findIndex(order => (order.id === updatedOrder.id))

      // guard for missing data
      if (existingOrderIndex) {
        // replace the old order with the updated order
        prev[existingOrderIndex] = updatedOrder
        // return orders with new, updated data
        return prev
      }

      return prev
    },
  })
}

如果你能给我提供一个最小可行的回购协议,我很乐意与你一起完成它。我上周大部分时间都在处理订阅问题:)

于 2017-10-16T20:20:02.347 回答