[英]Mutation updates apollo cache but cache update not reflected in UI
I'm using Apollo Client with React, I've outlined my Query
/ Mutation
usage in the MWE below.我在 React 中使用 Apollo Client,我在下面的 MWE 中概述了我的
Query
/ Mutation
用法。
I have a Query
which fetches a user's appointments:我有一个
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>
The BookingsBlock
is represented by this MWE: 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>
)
}
}
From the above, BookingBlock
and EmptyBookingBlock
are simply styled components without any logic.从上面可以看出,
BookingBlock
和EmptyBookingBlock
是简单的样式组件,没有任何逻辑。
The Appointment
component is as in this following MWE: 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>
)
}
Again, AppointmentBlock
, Description
and Value
are simply styled components without logic.同样,
AppointmentBlock
、 Description
和Value
是没有逻辑的简单样式组件。 CancelAppointment
is a component represented by the following MWE, which cancels the appointment via a Mutation
: 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>
)
}
}
}
Once more CancelAppointmentButtonInactive
and CancelAppointmentButtonActive
are button styled components. CancelAppointmentButtonInactive
和CancelAppointmentButtonActive
是按钮样式的组件。
The mutation functions as expected and cancels the appointment on the database.突变按预期运行并取消数据库上的约会。 After the mutation function is called the Apollo cache is updated in browser memory to reflect the appointment being cancelled.
调用变异函数后,Apollo 缓存会在浏览器内存中更新,以反映被取消的约会。 I have tested this using the Apollo dev tools.
我已经使用 Apollo 开发工具对此进行了测试。
However this change in appointment status is not reflected in the UI, in particular the status displayed in Appointment
→ AppointmentBlock
does not update to cancelled.但是,约会状态的这种更改不会反映在 UI 中,尤其是在
Appointment
→ AppointmentBlock
中显示的状态不会更新为已取消。 The CancelAppointment
button also does not receive an update to its this.props.status
as one would expected when the appointment is updated in the cache via the completed mutation. CancelAppointment
按钮也不会像预期的那样接收到this.props.status
的更新,因为当约会通过已完成的this.props.status
在缓存中更新时。
I initially thought this may be down to query/mutation object return object differences, but even after unifying what fields are returned the UI does not update.我最初认为这可能归结为查询/变异对象返回对象的差异,但即使在统一返回哪些字段后,UI 也不会更新。
The data flow of the appointment data is Query 'GET_USER_APPOINTMENTS'
→ BookingBlock
→ Appointment
→ CancelAppointment
.预约数据的数据流向为
Query 'GET_USER_APPOINTMENTS'
→ BookingBlock
→ Appointment
→ CancelAppointment
。
Your BookingsBlock
component is copying first props
into own state
, therefore change in the props
, caused by the mutation, is not affecting the rendered state.您的
BookingsBlock
组件正在将第一个props
复制到自己的state
,因此由突变引起的props
更改不会影响渲染状态。 Simply getting rid of the state
in BookingsBlock
will help - it's not needed in there anyway, as you can easily calculate both pastAppointments
and futureAppointments
in the render
method.简单地摆脱
BookingsBlock
中的state
会有所帮助 - 无论如何都不需要它,因为您可以轻松地在render
方法中计算pastAppointments
和futureAppointments
。
First you have to change the fetch policy in GET_USER_APPOINTMENTS.首先,您必须更改 GET_USER_APPOINTMENTS 中的获取策略。 cache-first is default .
cache-first 是 default 。 network-only always fetches form server it does not look in cache first.
network-only 总是从服务器获取它不会首先在缓存中查找。
Second .. after mutation you have to update the cache.第二个 .. 突变后,您必须更新缓存。
check this link from off [ https://www.apollographql.com/docs/react/essentials/mutations.html#update][1]从关闭检查此链接 [ https://www.apollographql.com/docs/react/essentials/mutations.html#update][1]
hope this will help.希望这会有所帮助。 stay blessed :)
祝好运 :)
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.