Issue with automatic UI updates in Apollo: `updateQuery` not working properly with `subscribeToMore`

ⅰ亾dé卋堺 提交于 2019-12-25 07:46:55

问题


I'm using GraphQL subscriptions for my chat application, but I have an issue with the UI updates.

Here are the query and the mutation I'm using:

const createMessage = gql`
    mutation createMessage($text: String!, $sentById: ID!) {
        createMessage(text: $text, sentById: $sentById) {
            id
            text
        }
    }
`

const allMessages = gql`
    query allMessages {
        allMessages {
            id
            text
            createdAt
            sentBy {
                name
                location {
                    latitude
                    longitude
                }
            }
        }
    }
`

Then, when exporting, I'm wrapping my Chat component like so:

export default graphql(createMessage, {name : 'createMessageMutation'})(
  graphql(allMessages, {name: 'allMessagesQuery'})(Chat)
)

I'm subscribing to the allMessagesQuery in componentDidMount:

componentDidMount() {

  // Subscribe to `CREATED`-mutations
  this.createMessageSubscription = this.props.allMessagesQuery.subscribeToMore({
    document: gql`
        subscription {
            Message(filter: {
                mutation_in: [CREATED]
            }) {
                node {
                    id
                    text
                    createdAt
                    sentBy {
                        name
                    }
                }
            }
        }
    `,
    updateQuery: (previousState, {subscriptionData}) => {
      console.log('Chat - received subscription: ', previousState, subscriptionData)
      const newMessage = subscriptionData.data.Message.node
      const messages = previousState.allMessages.concat([newMessage])
      console.log('Chat - new messages: ', messages.length, messages) // prints the correct array with the new message!!
      return {
        allMessages: messages
      }
    },
    onError: (err) => console.error(err),
  })

}

After I sent the message through the chat, the subscription is triggered successfully and I see the two logging statements that also contain the expected data. So the contents of messages are definitely correct within updateQuery!

However, the UI doesn't update automatically, in fact, all the previously displayed messages disappear.

My render method looks as follows:

render() {
  console.log('Chat - render: ', this.props.allMessagesQuery)
  return (
    <div className='Chat'>
      <ChatMessages
        messages={this.props.allMessagesQuery.allMessages || []}
      />
      <ChatInput
        message={this.state.message}
        onTextInput={(message) => this.setState({message})}
        onResetText={() => this.setState({message: ''})}
        onSend={this._onSend}
      />
    </div>
  )
}

The logging statement in render shows that initially, this.props.allMessagesQuery has the array allMessages, so everything works after the initial loading.

After the subscription is received, allMessages disappears from this.props.allMessagesQuery which is why an empty array is given to ChatMessages and nothing is rendered.

Before subscription is triggered

After subscription is triggered


回答1:


I figured it out after digging through the docs one more time, it was a mistake on my end!

This part from the Apollo docs helped me solve the issue:

Remember: You'll need to ensure that you select IDs in every query where you need the results to be normalized.

So, adding the id fields to the returned payload of my queries and subscriptions actually helped.

const allMessages = gql`
    query allMessages {
        allMessages {
            id
            text
            createdAt
            sentBy {
                id
                name
                location {
                    id
                    latitude
                    longitude
                }
            }
        }
    }
`

subscription {
    Message(filter: {
        mutation_in: [CREATED]
    }) {
         node {
            id
            text
            createdAt
            sentBy {
                id
                name
            }
        }
    }
}



回答2:


In your update Query the previousState is the allMessages query that is saved in the react apollo store.

To update the store you have to make a deep copy or use some helper e.g. reacts immutability helper. The apollo developers page gives some information about how to update the store correctly update Query.

In your case it could look like this

...
updateQuery: (previousState, { subscriptionData }) => {
  const newMessage = subscriptionData.data.Message.node;
  return update(previousState, {
    allMessages: { $push: [newMessage] },
  });
}
...


来源:https://stackoverflow.com/questions/42492943/issue-with-automatic-ui-updates-in-apollo-updatequery-not-working-properly-wi

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!