我在一个react项目中使用apollo,并在创建、更新和删除对象时使用订阅。我使用了 subscribeToMore
功能来启动订阅。该 prev
的价值 updateQuery
回调是创建和删除订阅的正确值。但是对于更新订阅来说 prev
值已经包含了更新后的值。总的来说,这真的很好,因为我不需要添加我的自定义实现如何更新对象,而只需要用 return prev
但我不明白为什么会发生这种情况。根据我的理解,应该返回之前的值。这是apollo的后备功能还是什么奇怪的错误?
这里是实现订阅的组件。
import { useEffect } from 'react';
import { useQuery } from '@apollo/react-hooks';
import * as Entities from './entities';
import * as Queries from './queries';
interface IAppointmentData {
appointments: Entities.IAppointment[];
error: boolean;
loading: boolean;
}
function getAppointmentsFromData(data) {
return (data && data.appointments) || [];
}
export function useAllAppointments(): IAppointmentData {
const initialResult = useQuery(Queries.GET_APPOINTMENTS);
const { data, error, loading, subscribeToMore } = initialResult;
useEffect(() => {
const unsubscribeNewAppointments = subscribeToMore({
document: Queries.NEW_APPOINTMENTS_SUB,
variables: {},
updateQuery: (prev, { subscriptionData }) => {
if (!subscriptionData.data) {
return prev;
}
const { newAppointment } = subscriptionData.data;
return Object.assign({}, prev, {
appointments: [...prev.appointments, newAppointment],
});
},
});
const unsubscribeUpdateAppointment = subscribeToMore({
document: Queries.UPDATE_APPOINTMENTS_SUB,
variables: {},
updateQuery: (prev, { subscriptionData }) => {
return prev
},
});
const unsubscribeDeleteAppointments = subscribeToMore({
document: Queries.DELETE_APPOINTMENTS_SUB,
variables: {},
updateQuery: (prev, { subscriptionData }) => {
if (!subscriptionData.data) {
return prev;
}
const { deleteAppointment: {
id: deletedAppointmentId
} } = subscriptionData.data;
return Object.assign({}, prev, {
appointments: prev.appointments.filter(item => item.id !== deletedAppointmentId),
});
},
});
return function unsubscribe() {
unsubscribeNewAppointments()
unsubscribeDeleteAppointments()
unsubscribeUpdateAppointment()
}
}, [subscribeToMore]);
return {
appointments: getAppointmentsFromData(data),
error: !!error,
loading,
};
}
这些是我的graphql查询订阅。
import { gql } from 'apollo-boost';
export const GET_APPOINTMENTS = gql`
{
appointments {
id
responsibleCustomer {
id
user {
id
firstName
lastName
}
}
companions {
id
user {
id
firstName
lastName
}
}
time {
plannedStart
plannedEnd
}
type
}
}
`;
export const NEW_APPOINTMENTS_SUB = gql`
subscription newAppointment {
newAppointment {
id
responsibleCustomer {
id
user {
id
firstName
lastName
}
}
companions {
id
user {
id
firstName
lastName
}
}
time {
plannedStart
plannedEnd
}
type
}
}
`;
export const UPDATE_APPOINTMENTS_SUB = gql`
subscription updateAppointment {
updateAppointment {
id
responsibleCustomer {
id
user {
id
firstName
lastName
}
}
companions {
id
user {
id
firstName
lastName
}
}
time {
plannedStart
plannedEnd
}
type
}
}
`;
export const DELETE_APPOINTMENTS_SUB = gql`
subscription deleteAppointment {
deleteAppointment {
id
}
}
`;
根据官方的Apollo 文件
需要注意的是,updateQuery回调必须返回一个与初始查询数据形状相同的对象,否则新数据不会被合并。
在玩了一下之后,似乎如果在查询数据的时候使用 身份证 你返回的对象和你缓存中的对象是一样的,而且对象的形状也是一样的,更新就会自动发生。
但是如果你真的按照我的链接中的CommentsPage例子来做的话 只要 你会发现,返回的id是 新的这就是为什么他们会明确地将新数据分配给对象。
if (!subscriptionData.data) return prev;
const newFeedItem = subscriptionData.data.commentAdded;
return Object.assign({}, prev, {
entry: {
comments: [newFeedItem, ...prev.entry.comments]
}
});
我已经在我自己的消息应用中测试过了,当接收到新的消息时,会有新的数据。身份证 我必须自己返回合并后的数据,但当我更新聊天室以显示哪个聊天室应该在我的屏幕顶部时(哪个聊天室有最新的消息),我的更新就会自动发生,我只是返回prev。但是当我更新chatRooms来显示哪个chatRooms应该在我的屏幕顶部(哪一个有最新的消息)时,我的更新就会自动发生,我只是返回prev。
如果您想在更新之前明确地检查数据,您可以尝试以下方法。变通办法 我在GitHub上找到的。你只需要用一个反向查找的方法 身份证 或者只是一个不同的变量,而不是 身份证.
在你的例子中,我就是这样做的。
updateAppointment {
// was id
idUpdateAppointment // im sure updateAppointmentId should also work... i think
responsibleCustomer {
id
user {
id
firstName
lastName
}
}
}