为什么 react Apollo 在更新订阅时,会将已经更新的值返回为 prev?

问题描述 投票:1回答:1

我在一个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
    }
  }
`;
reactjs publish-subscribe react-apollo
1个回答
0
投票

根据官方的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
    }
  }
}
© www.soinside.com 2019 - 2024. All rights reserved.