Apollo中自动UI更新的问题:`updateQuery`与`subscribeToMore`无法正常工作

时间:2017-02-27 18:15:50

标签: javascript graphql apollo apollostack react-apollo

我正在为我的聊天应用程序使用 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)
)

我正在订阅allMessagesQuery中的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),
  })

}

通过聊天发送消息后,订阅成功触发,我看到两个日志语句也包含预期的数据。因此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,因此在初始加载后一切正常。

收到订阅后,allMessagesthis.props.allMessagesQuery 消失,这就是为ChatMessages提供空数组并且不呈现任何内容的原因。

在触发订阅之前

enter image description here

触发订阅后

enter image description here

2 个答案:

答案 0 :(得分: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
            }
        }
    }
}

答案 1 :(得分:0)

在您的更新查询中,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] },
  });
}
...