突变更新了阿波罗缓存,但缓存更新未反映在用户界面中

时间:2019-01-09 14:08:06

标签: javascript reactjs apollo react-apollo apollo-client

我将Apollo Client与React结合使用,我在下面的MWE中概述了Query / Mutation的用法。

我有一个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>
    )
  }
}

从上面看,BookingBlockEmptyBookingBlock是样式简单的组件,没有任何逻辑。

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>
  )
}

同样,AppointmentBlockDescriptionValue是没有逻辑的简单样式化的组件。 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>
      )
    }
  }
}

有更多CancelAppointmentButtonInactiveCancelAppointmentButtonActive是按钮样式的组件。

该突变将按预期运行,并取消数据库上的约会。调用了变异函数后,将在浏览器内存中更新Apollo缓存,以反映约会被取消。我已经使用Apollo开发工具对此进行了测试。

但是,约会状态的这种更改未反映在UI中,特别是AppointmentAppointmentBlock中显示的状态不会更新为已取消。 CancelAppointment按钮也未收到其this.props.status的更新,这是通过完成的突变在缓存中更新约会时所期望的。

我最初认为这可能是由于查询/变异对象返回对象的差异,但即使统一返回哪些字段,UI也不会更新。

约会数据的数据流是Query 'GET_USER_APPOINTMENTS'BookingBlockAppointmentCancelAppointment

2 个答案:

答案 0 :(得分:1)

您的BookingsBlock组件正在复制 first props到自己的state中,因此props的变化不会引起突变影响渲染状态。简单地摆脱state中的BookingsBlock会有所帮助-无论如何都不需要,因为您可以轻松地在pastAppointments中计算futureAppointmentsrender方法。

答案 1 :(得分:0)

首先,您必须在GET_USER_APPOINTMENTS中更改获取策略。默认为cache-first。仅限网络的总是获取不首先在缓存中查找的表单服务器。

第二..突变后,您必须更新缓存。

从关闭检查此链接  [https://www.apollographql.com/docs/react/essentials/mutations.html#update][1]

希望这会有所帮助。 保持祝福:)