Apollo 中的自动 UI 更新问题:`updateQuery` 不能与 `subscribeToMore` 一起正常工作
Posted
技术标签:
【中文标题】Apollo 中的自动 UI 更新问题:`updateQuery` 不能与 `subscribeToMore` 一起正常工作【英文标题】:Issue with automatic UI updates in Apollo: `updateQuery` not working properly with `subscribeToMore` 【发布时间】:2017-07-18 11:46:57 【问题描述】:我正在为我的聊天应用程序使用 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
一个空数组而没有渲染的原因。
订阅触发前 ✅
订阅触发后 ❌
【问题讨论】:
【参考方案1】:我又翻了一遍文档才发现,这是我的错误!
Apollo docs 的这一部分帮助我解决了这个问题:
请记住:您需要确保在需要对结果进行规范化的每个查询中选择 ID。
因此,将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
【讨论】:
【参考方案2】:在您的更新查询中,previousState 是保存在 react apollo 存储中的 allMessages 查询。
要更新商店,您必须进行深层复制或使用一些帮助程序,例如reacts immutability helper。 apollo 开发者页面提供了一些关于如何正确更新商店的信息update Query。
在你的情况下,它可能看起来像这样
...
updateQuery: (previousState, subscriptionData ) =>
const newMessage = subscriptionData.data.Message.node;
return update(previousState,
allMessages: $push: [newMessage] ,
);
...
【讨论】:
以上是关于Apollo 中的自动 UI 更新问题:`updateQuery` 不能与 `subscribeToMore` 一起正常工作的主要内容,如果未能解决你的问题,请参考以下文章
Apollo 客户端 writeQuery 更新存储,但 UI 组件仅在第二次函数调用后更新
在 Apollo-client 中,writeQuery 会更新缓存,但 UI 组件不会重新渲染