2017-10-15 10 views
1

サブスクリプションとリアルタイム更新の一般的なアプローチを理解するには、何か助けが必要です。私はReact Nativeアプリを持っていて、ApolloとGraphcoolサービスをバックエンドとして使っています。Reactアプリケーションでサブスクリプションにアクセスする方法

アプリを見ているユーザーが何か変わったというプッシュ通知を受け取るシナリオがいくつかあります。もちろん、画面データも更新されるはずです。サブスクリプションはその仕事の明白な候補者であり、本質的に働いています。

私はこのようなサブスクリプションを持っています。これは、単独でうまく動作します(Googleマップ上でプレイヤーのアバターを配置するために使用されます)。

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

そしてものを更新するには、このクエリを実行する(簡単にするために)アポロからrefetchQueriesと共に突然変異createPlayerを実行する別のアプリ画面があります。これが完了すると

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の別のサブスクリプションも設定する必要がありますか?

答えて

2

私は(ないアポロの専門家)を推測していた場合、私はあなたがパラメータとしてクエリではなくサブスクリプションを使用しているようにそれはそう(あなたのsubscribeToMoreのいずれかで間違ったdocument入力に関係していますよね? )またはupdateQuerysubscribeToMoreにある場合、更新されたデータが返されます。

orderChangedサブスクリプションでOrderの変更をリッスンしています。更新を受け取ったら、ordersクエリの注文を更新された注文に置き換えます。あなたが最小の実行可能なレポを私に提供することができれば

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 
    }, 
    }) 
} 

すると、私は通じ仕事させていただきます:私たちはsubscribeToMoreupdateQuery機能でそう(タイプミスについて謝罪、これは正確なコピー&ペーストではありません)それはあなたと一緒に。私は先週の購読の多くを費やして過ごしました:)

+0

「updateQuery」はちょっと必要です。なぜ私は、Apolloが型と 'dataIdFromObject'に基づいて独自の結果ストアを更新するという印象を得たのか分かりません。しかたがない。私のような深く入れ子構造に '不変ヘルパー 'を使用しなければならなかったのですが、今のところうまくいくようです。ありがとう – FredyC

関連する問題