我将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>
)
}
}
从上面看,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开发工具对此进行了测试。
但是,约会状态的这种更改未反映在UI中,特别是Appointment
→AppointmentBlock
中显示的状态不会更新为已取消。 CancelAppointment
按钮也未收到其this.props.status
的更新,这是通过完成的突变在缓存中更新约会时所期望的。
我最初认为这可能是由于查询/变异对象返回对象的差异,但即使统一返回哪些字段,UI也不会更新。
约会数据的数据流是Query 'GET_USER_APPOINTMENTS'
→BookingBlock
→Appointment
→CancelAppointment
。
答案 0 :(得分:1)
您的BookingsBlock
组件正在复制 first props
到自己的state
中,因此props
的变化不会引起突变影响渲染状态。简单地摆脱state
中的BookingsBlock
会有所帮助-无论如何都不需要,因为您可以轻松地在pastAppointments
中计算futureAppointments
和render
方法。
答案 1 :(得分:0)
首先,您必须在GET_USER_APPOINTMENTS中更改获取策略。默认为cache-first。仅限网络的总是获取不首先在缓存中查找的表单服务器。
第二..突变后,您必须更新缓存。
从关闭检查此链接 [https://www.apollographql.com/docs/react/essentials/mutations.html#update][1]
希望这会有所帮助。 保持祝福:)