Компонент подписки с GraphQL Apollo Client

У меня есть приложение с одной подпиской, уже использующее subscribeToMore

Компонент запроса:

<Query query = {GET_MESSAGES}>
  {({ data, subscribeToMore }) => {
    return (
      <MessageList
        messages = {data.allMessages}
        subscribeToMore = {subscribeToMore}/>
    );
  }}
</Query>

Этот запрос загружает список сообщений, где, насколько я знаю, мы присоединяем подписчика к ComponentDidMount, поэтому всякий раз, когда я добавляю новый элемент в свой список внутри запроса, моя подписка будет прослушивать подписку и делать все, что я хочу (в данном случае добавить новое сообщение в мой текущий список сообщений).

Компонент "Список сообщений":

export default class MessageList extends React.Component {
componentDidMount() {
  this.props.subscribeToMore({
    document: MESSAGE_CREATED,
    updateQuery: (prev, { subscriptionData }) => {
      if (!subscriptionData.data) return prev;
      return {
        allMessages: [
          subscriptionData.data.messageCreated,
          ...prev.allMessages
        ],
      };
    },
  });
}

render() {
  return (
    <div>
      {this.props.messages.map(message => (
        <MessageElement key = {message.id} 
                        message = {message}/>
      ))}
    </div>
  );
}}

Я хочу добавить еще одну подписку, чтобы при редактировании сообщения информация обновлялась в реальном времени. Для этого я создал следующий компонент, используя Подписка

Компонент сообщения (где я хотел бы добавить еще одну подписку на основе обновленного сообщения)

export default class MessageElement extends Component{

componentDidMount() {
    this.messageUpdatedSubscription();
}


messageUpdatedSubscription = () => (
    <Subscription
      subscription = {MESSAGE_UPDATED}>
      {({ data: { messageUpdated } }) => (
        console.info('Do smthg???',messageUpdated)
      )}
    </Subscription>
  );


render(){
    return(
        <Mutation mutation = {UPDATE_MESSAGE} key = {this.props.message.id}>
         {updateMessage => (
            <div>
                <div>{this.props.message.text}</div> 
                <div>
                    <Star active = {this.props.message.isFavorite} 
                         onClick = {() => { updateMessage({ variables: { 
                                          id: this.props.message.id, 
                                          text:this.props.message.text,
                                          isFavorite:!this.props.message.isFavorite } });
                    }}/>
                </div>
            </div>
          )}
       </Mutation>);
}}

Мои подписки на сервере работают, так как у меня уже есть подписка на MESSAGE_CREATED в запросе, работающем правильно, и я проверил, что на сервере срабатывает моя подписка на MESSAGE_UPDATED. Однако я не могу понять, почему пользовательский интерфейс не отображает или console.info ничего, как будто он не прослушивает подписку.

Могу ли я добиться этого с помощью компонента подписки или subscribeToMore?

заранее спасибо

Пользовательский скаляр GraphQL
Пользовательский скаляр GraphQL
Листовые узлы системы типов GraphQL называются скалярами. Достигнув скалярного типа, невозможно спуститься дальше по иерархии типов. Скалярный тип...
Что такое Apollo Client и зачем он нужен?
Что такое Apollo Client и зачем он нужен?
Apollo Client - это полнофункциональный клиент GraphQL для JavaScript-приложений, который упрощает получение, управление и обновление данных в...
1
0
1 563
2

Ответы 2

Компонент подписки не может быть запущен в ComponentDidMount. Он должен находиться в методе жизненного цикла render (). Его параметр можно использовать в ComponentDidMount, но не в компоненте.

Я могу придумать 3 возможных решения:

1) Вы можете попробовать поместить метод подписки в свой метод рендеринга. Вам просто нужно вложить это внутри или снаружи вашего компонента Мутации.

2) Вы можете инициировать компонент подписки в родительском элементе этого компонента и передать его параметр (messageUpdate) компоненту MessageElement. Затем вы можете использовать messageUpdate вне реквизита в ComponentDidMount.

3) Вы можете использовать компонент высшего порядка Apollo. Затем вы можете получить доступ к messageUpdate в реквизитах. (Отказ от ответственности - я не пробовал это раньше).

Надеюсь, это поможет!

Спасибо @ cory-mcaboy. В конечном итоге я решил проблему с помощью вашего первого предложения, вложив свою Подписку в мою Мутацию.

itReverie 13.08.2018 18:14

Основываясь на предложении @ cory-mcaboy, я вложил свою подписку в мутацию. Я также обнаружил, что, поскольку у меня есть список сообщений, я просто хотел активировать подписку на основе сообщения, которое я обновляю, а не всего списка; Мне пришлось изменить подписку на бэкэнде и во фронтэнде следующим образом:

Схема сервера

const typeDefs = gql` type Subscription {
                      messageUpdated(id: Int!): Message}`;

Серверный преобразователь

 Subscription: {
    messageUpdated: {
        subscribe: withFilter(
                   () => pubsub.asyncIterator([MESSAGE_UPDATED]),
                         (payload, variables) => {
                         return payload.messageUpdated.id === variables.id;
                                        },
                   ),
      },
}

Клиентский компонент

const MESSAGE_UPDATED = gql` subscription messageUpdated($id: Int!){
            messageUpdated(id:$id)
            { 
                id
                text
                isFavorite
            }}`;

export default class MessageElement extends Component{
render(){
    return(<Mutation mutation = {UPDATE_MESSAGE} key = {this.props.message.id}>
            {updateMessage => (
                <div>
                    <div>{this.props.message.text}</div> 
                     <Subscription subscription = {MESSAGE_UPDATED}
                                   variables = {{ id: this.props.message.id }}>
                        {() => {
                            return <Star active = {this.props.message.isFavorite} 
                                        onClick = {() => { updateMessage({ variables: { 
                                                                        id: this.props.message.id, 
                                                                        text: this.props.message.text,
                                                                        isFavorite: !this.props.message.isFavorite } });}}/>
                        }}
                    </Subscription>
                </div>
            )}
        </Mutation>
    );
}}

Вы можете увидеть код в следующем репо: back-end итр-аполлон-сервер, front-end itr-apollo-client

Другие вопросы по теме