javascript - 突变更新 apollo 缓存但缓存更新未反射(reflect)在 UI 中

标签 javascript reactjs apollo react-apollo apollo-client

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

我有一个获取用户约会的查询:

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 缓存在浏览器内存中更新以反射(reflect)约会被取消。我已经使用 Apollo 开发工具对此进行了测试。

但是,约会状态的这种变化并未反射(reflect)在 UI 中,特别是 AppointmentAppointmentBlock 中显示的状态不会更新为已取消。 CancelAppointment 按钮也没有收到对其 this.props.status 的更新,正如人们预期的那样,当通过完成的突变在缓存中更新约会时。

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

预约数据的数据流为Query 'GET_USER_APPOINTMENTS'BookingBlockAppointmentCancelAppointment

最佳答案

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

关于javascript - 突变更新 apollo 缓存但缓存更新未反射(reflect)在 UI 中,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/54112011/

相关文章:

javascript - 为什么不显示在 react ?

node.js - webpack-dev-server 找不到模块 'webpack'

graphql - 使用 "operationName"和 "variables"向 apollo 服务器发送 POST 请求

javascript - Apollo 奇怪地改变了查询结果

javascript - 打印 [object HTMLInputElement] 而不是文本框

javascript - Highcharts 自定义符号图例

javascript - float 的列样式对齐

javascript - 在 JsRender 中创建变量的好方法是什么?

reactjs - 将主页设置为 package.json 中的变量并使其有条件地更改

javascript - React Native 和 Apollo : Can't find variable: document