我将 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>
)
}
}
从上面可以看出,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 缓存在浏览器内存中更新以反射(reflect)约会被取消。我已经使用 Apollo 开发工具对此进行了测试。
但是,约会状态的这种变化并未反射(reflect)在 UI 中,特别是 Appointment
→ AppointmentBlock
中显示的状态不会更新为已取消。 CancelAppointment
按钮也没有收到对其 this.props.status
的更新,正如人们预期的那样,当通过完成的突变在缓存中更新约会时。
我最初认为这可能归结为查询/变异对象返回对象的差异,但即使在统一返回哪些字段之后,UI 也不会更新。
预约数据的数据流为Query 'GET_USER_APPOINTMENTS'
→ BookingBlock
→ Appointment
→ CancelAppointment
。
最佳答案
您的 BookingsBlock
组件正在将 first props
复制到自己的 state
中,因此更改 props
,由突变引起,不影响渲染状态。简单地摆脱 BookingsBlock
中的 state
会有所帮助 - 无论如何都不需要它,因为您可以轻松计算 pastAppointments
和
。render
方法中的 futureAppointments
关于javascript - 突变更新 apollo 缓存但缓存更新未反射(reflect)在 UI 中,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/54112011/