У меня есть приложение с одной подпиской, уже использующее 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?
заранее спасибо


Компонент подписки не может быть запущен в ComponentDidMount. Он должен находиться в методе жизненного цикла render (). Его параметр можно использовать в ComponentDidMount, но не в компоненте.
Я могу придумать 3 возможных решения:
1) Вы можете попробовать поместить метод подписки в свой метод рендеринга. Вам просто нужно вложить это внутри или снаружи вашего компонента Мутации.
2) Вы можете инициировать компонент подписки в родительском элементе этого компонента и передать его параметр (messageUpdate) компоненту MessageElement. Затем вы можете использовать messageUpdate вне реквизита в ComponentDidMount.
3) Вы можете использовать компонент высшего порядка Apollo. Затем вы можете получить доступ к messageUpdate в реквизитах. (Отказ от ответственности - я не пробовал это раньше).
Надеюсь, это поможет!
Основываясь на предложении @ 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
Спасибо @ cory-mcaboy. В конечном итоге я решил проблему с помощью вашего первого предложения, вложив свою Подписку в мою Мутацию.