【问题标题】:Why does react Apollo on update subscription returns the already updated value as prev?为什么 React Apollo on update subscription 返回已经更新的值作为 prev?
【发布时间】:2020-01-17 04:35:09
【问题描述】:

我将 apollo 用于一个 react 项目,并订阅了对象的创建、更新和删除。我使用subscribeToMore 功能启动订阅。 updateQuery 回调的prev 值是创建和删除订阅的正确值。但是对于更新订阅,prev 值已经包含更新的值。总的来说,这真的很好,因为我不需要添加关于如何更新对象的自定义实现,只需return prev,但我不明白为什么会发生这种情况。据我了解,应该返回以前的值。这只是支持阿波罗的功能还是这是一些奇怪的错误?

这是实现订阅的组件:

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】:

    据阿波罗官方documentation

    注意,updateQuery 回调必须返回一个相同的对象 shape 作为初始查询数据,否则新数据不会 合并。

    玩了一会儿之后,如果您返回的 id 与缓存中的相同并且对象具有相同的形状,则似乎会自动更新。

    但是,如果您实际上遵循链接 I provided 中的 CommentsPage 示例,您会看到返回的 id 是 new,这就是他们明确为对象分配新数据的原因。

    if (!subscriptionData.data) return prev;
    const newFeedItem = subscriptionData.data.commentAdded;
    
    return Object.assign({}, prev, {
      entry: {
        comments: [newFeedItem, ...prev.entry.comments]
      }
    });
    

    我已经用我自己正在开发的消息应用程序对此进行了测试,当收到带有新 id 的新消息时,我必须自己返回合并的数据。但是当我更新聊天室以显示哪个聊天室应该在我的屏幕顶部(哪个有最新消息)时,我的更新会自动发生,我只是返回 prev。

    但是,如果您想在更新数据之前明确检查数据,您可以试试我在 GitHub 上找到的 workaround。您只需要使用反向查找 id 或只是 id 以外的其他变量。

    这就是我在您的示例中为实现这一目标所做的事情:

    updateAppointment {
      // was id
      idUpdateAppointment // im sure updateAppointmentId should also work... i think 
      responsibleCustomer {
        id
        user {
          id
          firstName
          lastName
        }
      }
    }
    

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2016-02-24
      • 2019-02-15
      • 1970-01-01
      • 2023-01-07
      • 2017-07-11
      • 2018-05-04
      • 2015-06-24
      • 2013-08-06
      相关资源
      最近更新 更多