Reputation: 934
Most examples use subscribeToMore within the query component but in my case the data returned by the query and subscription are very different so I think I need a discrete subscription component.
I have time series data being added to a database triggering onChangedWeatherIntervals
subscription which returns summary info about the new time series info. If the new time series info matches the React client's filters it should request an updated histogram getHistogram
query.
My test code:
<Query
query={gql`
{
getHistogram (deviceID:"ARMS-NVM-P16", startTimestamp:1525201056) {
columns {
binWidth
binHeight
binCenter
}
}
}
`}
>
{({
loading: queryLoading,
error: queryError,
data: queryData,
refetch
}) => (
<Subscription
subscription={gql`
subscription onChangedWeatherIntervals {
onChangedWeatherIntervals {
changedItems {
deviceID
timestamp
siteKey
}
}
}
`}>
{({
data: subscriptionData,
loading: subscriptionLoading,
error: subscriptionError
}) => {
if (subscriptionData && !subscriptionLoading) {
console.log("subscriptionData: ", subscriptionData);
//TODO: Add code to inspect subscriptionData & determine if we refetch
//refetch() //Uncommenting causes refetch loop after first server push
}
if (queryData && !queryLoading) {
console.log("queryData: ", queryData.getHistogram.columns);
return (<p>{queryData.getHistogram.columns[0].binWidth}</p>);
}
return null
}}
</Subscription>
)
}
</Query>
Because subscriptionLoading
is true
only before the first server push after mounting, I'm not sure the best way to distinguish re-renders from new subscriptionData. Should I store subscriptionData
to state.subscriptionData
and compare the two on each render?
Is there a more elegant approach to all of this?
Upvotes: 1
Views: 1380
Reputation: 3482
Have you ever tried to use subscribeToMore on your Query? You can probably call refetch in its updateQuery prop.
UPDATE: I happened to face the same problem in my app and figured out a way to solve it. Feel free to check it out here. Basically you should avoid putting your subscription logic in a render method which will cause infinite refetch/re-rendering problem. The solution is to move the logic out of render method and put it into a lifecycle method like componentDidMount. That way subscribe won't be called again after a refetch is triggered.
Here's the code snippet for your case. (I used the hoc graphql from 'react-apollo' to help injecting query's refetch and subscribeToMore into props).
import { graphql } from 'react-apollo';
class YourComponent extends React.Component {
componentDidMount() {
const { data: { refetch, subscribeToMore }} = this.props;
this.unsubscribe = subscribeToMore({
document: <ON_CHANGED_WEATHER_INTERVALS>,
updateQuery: (prev) => {
refetch();
return prev;
},
});
}
componentWillUnmount() {
this.unsubscribe();
}
render() {
const { data: {queryData, loading, error } } = this.props;
if (loading || error) return null;
return <p>{queryData.getHistogram.columns[0].binWidth}</p>
}
}
export default graphql(GET_HISTOGRAM, {
options: {
variables: {
deviceID: 'ARMS-NVM-P16',
startTimestamp:1525201056,
},
},
})(YourComponent)
Upvotes: 1