Apollo 中的自动 UI 更新问题:`updateQuery` 无法与 `subscribeToMore` 一起正常工作
Issue with automatic UI updates in Apollo: `updateQuery` not working properly with `subscribeToMore`
我正在为我的聊天应用程序使用 GraphQL 订阅,但是 UI 更新有问题。
这是我正在使用的查询和突变:
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
}
}
}
}
`
然后,在导出时,我像这样包装我的 Chat
组件:
export default graphql(createMessage, {name : 'createMessageMutation'})(
graphql(allMessages, {name: 'allMessagesQuery'})(Chat)
)
我正在订阅 componentDidMount
中的 allMessagesQuery
:
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),
})
}
我通过聊天发送消息后,订阅成功触发,我看到两个日志语句也包含预期数据。所以messages
的内容在updateQuery
内肯定是正确的!
但是,UI 不会自动更新,事实上,所有以前显示的消息都会消失。
我的 render
方法如下所示:
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>
)
}
render
中的日志语句显示,最初,this.props.allMessagesQuery
具有数组 allMessages
,因此在初始加载后一切正常。
收到订阅后,allMessages
从this.props.allMessagesQuery
中消失,这就是为什么给ChatMessages
一个空数组,什么都没有渲染。
订阅触发前 ✅
订阅触发后 ❌
在您的更新查询中,previousState 是保存在 React apollo 存储中的 allMessages 查询。
要更新商店,您必须制作深拷贝或使用一些帮助程序,例如reacts immutability helper. The apollo developers page gives some information about how to update the store correctly update Query.
在你的情况下它可能看起来像这样
...
updateQuery: (previousState, { subscriptionData }) => {
const newMessage = subscriptionData.data.Message.node;
return update(previousState, {
allMessages: { $push: [newMessage] },
});
}
...
我又翻了一遍文档才弄明白,这是我的一个错误!
Apollo docs 中的这部分帮助我解决了问题:
Remember: You'll need to ensure that you select IDs in every query where you need the results to be normalized.
因此,将 id
字段添加到我的查询和订阅的返回负载中实际上有所帮助。
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
}
}
}
}
我正在为我的聊天应用程序使用 GraphQL 订阅,但是 UI 更新有问题。
这是我正在使用的查询和突变:
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
}
}
}
}
`
然后,在导出时,我像这样包装我的 Chat
组件:
export default graphql(createMessage, {name : 'createMessageMutation'})(
graphql(allMessages, {name: 'allMessagesQuery'})(Chat)
)
我正在订阅 componentDidMount
中的 allMessagesQuery
:
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),
})
}
我通过聊天发送消息后,订阅成功触发,我看到两个日志语句也包含预期数据。所以messages
的内容在updateQuery
内肯定是正确的!
但是,UI 不会自动更新,事实上,所有以前显示的消息都会消失。
我的 render
方法如下所示:
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>
)
}
render
中的日志语句显示,最初,this.props.allMessagesQuery
具有数组 allMessages
,因此在初始加载后一切正常。
收到订阅后,allMessages
从this.props.allMessagesQuery
中消失,这就是为什么给ChatMessages
一个空数组,什么都没有渲染。
订阅触发前 ✅
订阅触发后 ❌
在您的更新查询中,previousState 是保存在 React apollo 存储中的 allMessages 查询。
要更新商店,您必须制作深拷贝或使用一些帮助程序,例如reacts immutability helper. The apollo developers page gives some information about how to update the store correctly update Query.
在你的情况下它可能看起来像这样
...
updateQuery: (previousState, { subscriptionData }) => {
const newMessage = subscriptionData.data.Message.node;
return update(previousState, {
allMessages: { $push: [newMessage] },
});
}
...
我又翻了一遍文档才弄明白,这是我的一个错误!
Apollo docs 中的这部分帮助我解决了问题:
Remember: You'll need to ensure that you select IDs in every query where you need the results to be normalized.
因此,将 id
字段添加到我的查询和订阅的返回负载中实际上有所帮助。
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
}
}
}
}