ApolloGraphQL и React: избегать вызова запроса и подписки при повторном монтировании компонента?

#reactjs #react-router #apollo #react-apollo #apollo-client

#reactjs #реагировать-маршрутизатор #apollo #реагировать-apollo #apollo-клиент

Вопрос:

У меня настроен маршрутизатор React следующим образом:

        <ApolloProvider client={ApolloClient}>
            <Router history={browserHistory}>
                <React.Suspense fallback={<p></p>}>
                    <ErrorBoundary>
                        <AppStateProvider>
                            <Route render={(routeProps) =>
                                <TopNav
                                    history={routeProps.history}
                                    match={routeProps.match}
                                />
                            }/>
                            <Switch>
                                <Route exact path="/" render={(routeProps) =>
                                    <myComponent history={routeProps.history} match={routeProps.match}
                                    />
                                }/>

                                [.....MORE COMPONENTS.....]

                            </Switch>
                            <Route render={(routeProps) =>
                                <BottomNav history={routeProps.history} match={routeProps.match}
                                />
                            }/>
                        </AppStateProvider>
                    </ErrorBoundary>
                </React.Suspense>
            </Router>
        </ApolloProvider>
  

<TopNav> Компонент содержит запрос Apollo и подписку:

 function TopNav(props) {

[.......]

let unsubscribeFromIncomingMessages = null; <=== re-runs when user changes routes

[.......]

       <Query query={INCOMING_MESSAGES_QUERY}
               variables={{"localUserId": Meteor.userId()}}>
            {({subscribeToMore, loading, error, data, refetch}) => {
                if (loading) {
                    return (
                        <div key="divLoading"></div>);
                } else {
                }
                if (error) {
                    return (
                        <div key="divError"></div>);
                }

                if (!unsubscribeFromIncomingMessages) {
                    unsubscribeFromIncomingMessages = subscribeToMore({
                        document: INCOMING_MESSAGES_SUBSCRIPTION_QUERY,
                        variables: {
                            "localUserId": Meteor.userId()
                        },
                        updateQuery: (prev, {subscriptionData}) => {
                            [.....HANDLE UPDATE DATA.....]
                        }
                    });
                }

                return (
                    <>
                    </>
                );

            }}
        </Query>
  

Когда клиент открывает другой маршрут в моем приложении, он <TopNav> повторно монтируется, что хорошо, но <Query> и подписка запускаются заново.

Каков правильный способ решения этой проблемы?

Обновить

Точка останова на моем сервере в запросе подписки попадает каждый раз, когда я перехожу на новую страницу на моем клиенте.

Это должно произойти? Если это так, отлично! Но если нет — я хотел бы это знать. 🙂

Ответ №1:

Сделайте переменную unsubscribeFromIncomingMessages глобальной и добавьте fetchPolicy='cache-first' <Query> .

РЕДАКТИРОВАТЬ: Упс, я полагаю, я должен был ожидать этого. Подписка прекратится, как только вы отклонитесь от маршрута, независимо от того, где вы сохраняете ссылку.

subscribeToMore будет выполняться каждый раз, когда вы вводите маршрут. Если вам не нужно иметь возможность остановить подписку, вам не нужно записывать ссылку на нее. Настройка подписки при входе обходится недорого.

Если вам нужна одна и та же подписка, активная на разных маршрутах, вам нужно будет запустить ее и на этих маршрутах.

Насколько я понимаю, подписка не повторяется каждый раз, она просто начинается с того места, где остановилась последняя подписка с теми же переменными и т.д.

Комментарии:

1. Это сработало! Интересно, что я использовал пару кнопок <a href=...> , и они заставили весь сайт перезагрузиться с нуля, включая повторное объявление глобальной переменной. Я заменил их на onClick={() => props.history.push(theHref)} , и это решило проблему.

2. Обновление — я понятия не имею, почему сначала казалось, что это работает, но перемещение его в глобальный, похоже, убивает подписку. Хммм….. Интересно, что еще может быть лучшей практикой здесь?

3. Спасибо за эту информацию. Не могли бы вы случайно сказать мне, то же самое в <Subscription> component — т. Е. Он повторно подписывается при каждом обновлении — и сам отписывается при каждом отключении компонента?

4. Да, это также остановится при каждом размонтировании компонента.