如何在React应用程序中处理订阅

时间:2017-10-15 12:51:17

标签: javascript reactjs graphql react-apollo graphcool

我需要一些帮助来弄清楚订阅和实时更新的一般方法是什么。我有一个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以及来自Apollo的refetchQueries(为简单起见),它运行此查询以更新内容。

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设置另一个订阅吗?

1 个答案:

答案 0 :(得分:2)

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

在我们的案例中,我们有orderChanged订阅,可以收听Order上的更改。收到更新后,我们希望将orders查询中的订单替换为更新后的订单。我们在updateQuery的{​​{1}}函数中执行此操作(对于拼写错误道歉,这不是一个精确的复制粘贴):

subscribeToMore

如果您能为我提供最低限度的可行回购,我很乐意与您合作。上周我花了很多时间来完成订阅:)