Обновление мутаций кеша apollo, но обновление кеша не отражается в интерфейсе - PullRequest
0 голосов
/ 09 января 2019

Я использую Apollo Client с React, я изложил мое использование Query / Mutation в MWE ниже.

У меня есть Query, который выбирает встречи пользователя:

const GET_USER_APPOINTMENTS = gql`
  query getUserAppointments {
    getUserAppointments {
      id
      appointmentStart
      appointmentEnd
      appointmentType
      status
    }
  }
`
// omitted code for brevity...

<Query query={GET_USER_APPOINTMENTS} fetchPolicy='network-only'>
  {({ loading, error, data }) => {
    if (loading) return <div>Loading...</div>
    if (error) return `Error ${error}`

    const appointments = data.getUserAppointments

    return <BookingsBlock appointments={appointments} />
  }}
</Query>

BookingsBlock представлено этим MWE:

export default class BookingsBlock extends Component {
  constructor (props) {
    super(props)
    let pastAppointments = []
    let futureAppointments = []
    if (props.appointments) {
      // assign past and future appointments
      props.appointments.forEach(appt => {
        if (moment(appt.appointmentStart) < moment()) {
          pastAppointments.push(appt)
        } else {
          futureAppointments.push(appt)
        }
      })
    }
    this.state = { pastAppointments, futureAppointments }
  }

  render () {
    let pastAppointmentsBlock
    let futureAppointmentsBlock

    const EmptyBlock = (
      <EmptyBookingBlock>
        <h3>You have no appointments!</h3>
      </EmptyBookingBlock>
    )

    if (this.state.pastAppointments.length) {
      pastAppointmentsBlock = (
        <BookingBlock>
          {this.state.pastAppointments.map(appt => {
            return <Appointment key={appt.id} appointmentData={appt} />
          })}
        </BookingBlock>
      )
    } else {
      pastAppointmentsBlock = EmptyBlock
    }

    if (this.state.futureAppointments.length) {
      futureAppointmentsBlock = (
        <BookingBlock>
          {this.state.futureAppointments.map(appt => {
            return <Appointment key={appt.id} appointmentData={appt} />
          })}
        </BookingBlock>
      )
    } else {
      futureAppointmentsBlock = EmptyBlock
    }

    return (
      <div>
        <h2>Your bookings</h2>
        {futureAppointmentsBlock}
        {pastAppointmentsBlock}
      </div>
    )
  }
}

Исходя из вышесказанного, BookingBlock и EmptyBookingBlock являются просто стилизованными компонентами без какой-либо логики.

Компонент Appointment такой же, как в следующем MWE:

const Appointment = props => {
  const { id, appointmentStart, appointmentEnd, status } = props.appointmentData
  return (
    <AppointmentBlock>
        <p>
          <Description>Start: </Description>
          <Value> {moment(appointmentStart).format('HH:mm')} </Value>
        </p>
        <p>
          <Description>End: </Description>
          <Value> {moment(appointmentEnd).format('HH:mm')} </Value>
        </p>
        <p>
          <Description>Status: </Description>
          <Value>
            {status === 'Confirmed' ? (
              <PositiveValue>Confirmed</PositiveValue>
            ) : (
              <NegativeValue>{status}</NegativeValue>
            )}
          </Value>
        </p>
        <CancelAppointment
          id={id}
          appointmentStart={appointmentStart}
          status={status}
        />
      </div>
    </AppointmentBlock>
  )
}

Опять же, AppointmentBlock, Description и Value - это просто стилизованные компоненты без логики. CancelAppointment - это компонент, представленный следующим MWE, который отменяет встречу через Mutation:

const CANCEL_APPOINTMENT = gql`
  mutation cancelAppointment($id: Int!) {
    cancelAppointment(id: $id) {
      id
      appointmentStart
      appointmentEnd
      appointmentType
      status
    }
  }
`

// code omitted for brevity...

class CancelAppointment extends Component {
  constructor (props) {
    super(props)
    const hoursUntilAppt = moment(this.props.appointmentStart).diff(
      moment(),
      'hours'
    )
    const cancellable =
      this.props.appointmentType === 'A'
        ? hoursUntilAppt > 72
        : hoursUntilAppt > 48

    this.state = {
      cancelled: this.props.status === 'Cancelled',
      cancellable,
      firstClick: false
    }
  }

  cancelAppointment = async (e, cancelAppointment) => {
    e.preventDefault()
    await cancelAppointment({
      variables: { id: this.props.id }
    })
  }

  render () {
    if (!this.state.cancelled) {
      if (!this.state.cancellable) {
        return (
          <CancelAppointmentButtonInactive>
            Cancellation period elapsed
          </CancelAppointmentButtonInactive>
        )
      }
      if (!this.state.firstClick) {
        return (
          <CancelAppointmentButtonActive
            onClick={() => {
              this.setState({ firstClick: true })
            }}
          >
            Cancel appointment
          </CancelAppointmentButtonActive>
        )
      } else if (this.state.firstClick) {
        return (
          <Mutation mutation={CANCEL_APPOINTMENT}>
            {cancelAppointment => {
              return (
                <CancelAppointmentButtonActive
                  onClick={e => this.cancelAppointment(e, cancelAppointment)}
                >
                  Are you sure?
                </CancelAppointmentButtonActive>
              )
            }}
          </Mutation>
        )
      }
    } else {
      return (
        <CancelAppointmentButtonInactive>
          Appointment cancelled
        </CancelAppointmentButtonInactive>
      )
    }
  }
}

Еще раз CancelAppointmentButtonInactive и CancelAppointmentButtonActive являются компонентами в виде кнопок.

Мутация работает как положено и отменяет встречу в базе данных. После вызова функции мутации кеш Apollo обновляется в памяти браузера для отражения отмены встречи. Я проверил это с помощью инструментов разработчика Apollo.

Однако это изменение статуса встречи не отражается в пользовательском интерфейсе, в частности, статус, отображаемый в AppointmentAppointmentBlock, не обновляется до отмененного. Кнопка CancelAppointment также не получает обновления до this.props.status, как и следовало ожидать, когда встреча обновляется в кэше с помощью завершенной мутации.

Сначала я думал, что это может быть связано с тем, что объект запроса / мутации возвращает объектные различия, но даже после объединения возвращаемых полей пользовательский интерфейс не обновляется.

Поток данных о встречах: Query 'GET_USER_APPOINTMENTS'BookingBlockAppointmentCancelAppointment.

Ответы [ 2 ]

0 голосов
/ 09 января 2019

Сначала вы должны изменить политику выборки в GET_USER_APPOINTMENTS. Кэш-первый по умолчанию. Только для сети всегда выбирает сервер форм, он не смотрит в кеш первым.

Второй .. после мутации вы должны обновить кеш.

проверьте эту ссылку от [https://www.apollographql.com/docs/react/essentials/mutations.html#update][1]

надеюсь, это поможет. будь благословен:)

0 голосов
/ 09 января 2019

Ваш BookingsBlock компонент копирует first props в собственное state, поэтому изменение props, вызванное мутацией, не влияет на состояние рендеринга. Поможет просто избавиться от state в BookingsBlock - там все равно не нужно, так как вы можете легко рассчитать pastAppointments и futureAppointments в методе render.

...