I'm using Apollo Client's <Query>
within a component that is re-rendered when state is changed within a lifecycle method. I wish to have my <Query>
component re-run the query because I know that data has changed.
It appears that Query component is using a cache that needs to be invalidated before query is re-run.
I'm using a wonky workaround that caches the refetch
callback from the render prop in the parent component, but it feels wrong. I'll post my approach in the answers if anyone is interested.
My code looks something like this. I removed loading
and error
handling from query as well as some other detail for brevity.
class ParentComponent extends React.Component {
componentDidUpdate(prevProps) {
if (this.props.refetchId !== prevProps.refetchId) {
const otherData = this.processData() // do something
this.setState({otherData}) // this forces component to reload
}
}
render() {
const { otherData } = this.state
return (
<Query query={MY_QUERY}>
{({ data }) => {
return <ChildComponent gqlData={data} stateData={otherData} />
}}
</Query>
)
}
}
How do I force <Query>
to fetch new data to pass to <ChildComponent>
?
Even though ParentComponent
re-renders when props or state change, Query
doesn't re-run. ChildComponent
gets an updated stateData
prop, but has a stale gqlData
prop. As I understand Apollo's query cache need to be invalidated, but I'm not sure.
Please note that passing refetch
to ChildComponent is not the answer because it only displays information from GraphQL and wouldn't know when to refetch. I don't want to introduce timers or otherwise complicate ChildComponent
to solve this - it doesn't need to know about this complexity or data fetching concerns.
I had almost a similar situation which I solved with fetchPolicy
attribute:
<Query fetchPolicy="no-cache"
...
The task was to load some details from server by clicking on a list item.
And if I wanted to add an action to force re-fetching the query (such as modifying the details), I first assigned the refetch
to this.refetch
:
<Query fetchPolicy="no-cache" query={GET_ACCOUNT_DETAILS} variables=... }}>
{({ data: { account }, loading, refetch }) => {
this.refetch = refetch;
...
And in the specific action that I wanted the refetch to happen, I called:
this.refetch();
It seems to me that the Query component doesn't necessarily need to be inside this ParentComponent
.
In that case, I would move the Query component up, since I would still be able to render other stuff while I don't have results in the ChildComponent
. And then I would have access to the query.refetch
method.
Note that in the example I added the graphql
hoc, but you can still use Query component around <ParentComponent />
.
class ParentComponent extends React.Component {
componentDidUpdate(prevProps) {
if (this.props.refetchId !== prevProps.refetchId) {
const otherData = this.processData() // do something
// won't need this anymore, since refetch will cause the Parent component to rerender)
// this.setState({otherData}) // this forces component to reload
this.props.myQuery.refetch(); // >>> Refetch here!
}
}
render() {
const {
otherData
} = this.state;
return <ChildComponent gqlData={this.props.myQuery} stateData={otherData} />;
}
}
export graphql(MY_QUERY, {
name: 'myQuery'
})(ParentComponent);
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With