-
Notifications
You must be signed in to change notification settings - Fork 774
After a query has resulted in an error, variable updates that should result in an Apollo QueryResult with no errors do not update the QueryResult's error field in componentWillReceiveProps #1749
Description
Actual Result
- Component mounts using
graphqlHOC, with a Query that produces an error - Update props so that variables passed to the operation options will now result in a query that succeeds with no errors
- No network request is made, and inside
componentWillReceiveProps, thenextProps.data.erroris still defined with the previous error
Intended Result
- Component mounts using
graphqlHOC, with a Query that produces an error - Update props so that variables passed to the operation options will now result in a query that succeeds with no errors
- Either a network request is made, or the data is returned from the cache such that
nextProps.data.erroris no longer defined
How am I testing this?
Good question. I have a basic query that requests a field that always succeeds, and another field that fails when included:
// query.gql
query SomeQuery($shouldFail: Boolean!) {
successField {
id
}
failField @include(if: $shouldFail) {
id
}
}
Now for my components. I have 2 components, one that acts as a parent and determines whether its child shouldFail or not so that the child gets prop updates, which trigger a variable update when the operation options are different.
// Child
class ChildPresentation extends React.Component<Props> { ... }
// Child connected to graphql HOC
const Child = graphql(query, {
options: (props: Props) => ({
variables: {
shouldFail: props.shouldFail,
},
}),
})(ChildPresentation);
// Parent
class Parent extends React.Component<ParentProps> {
public render() {
return <Child shouldFail={this.state.shouldFail} />;
}
}
With this set up, you can see how Parent can easily update its state, which causes Child's shouldFail prop to update, which causes the variable inside the operation options to update... and down the rabbit hole.
The rabbit hole
When a GraphQL error comes through, the Observable decides to clean itself up.
Which removes it from ObservableQuery's list of observers (emptying it).
Then when the new query variables come in, it follows the path of:
GraphQL.componentWillReceivePropsGraphQL.updateQuery(https://github.com/apollographql/react-apollo/blob/apollo-client-2.0/src/graphql.tsx#L220)ObservableQuery.setOptions(https://github.com/apollographql/react-apollo/blob/apollo-client-2.0/src/graphql.tsx#L391)ObservableQuery.setVariables(https://github.com/apollographql/apollo-client/blob/2.0/packages/apollo-client/src/core/ObservableQuery.ts#L396)
Which would normally end up doing the network request, but since earlier the observers list became empty, this ends up being a no-op.
Then there's no recovery from react-apollo's perspective; when the graphql hoc calls subscribeToQuery at the end of componentWillReceiveProps (after the GraphQL.updateQuery above), that's a no-op because from its perspective it thinks it's still subscribed.
https://github.com/apollographql/react-apollo/blob/apollo-client-2.0/src/graphql.tsx#L432
The above was found and documented after some minor digging to see why this was happening.
Repro Environment
I actually don't have an easily accessible repro environment with public data that can be used for this. Though it should be fairly straightforward to set up by following my components above.
Version
- react-apollo@2.1.0-beta.3
- apollo-client@2.2.5
- react@16.2.0