Urql: Subscription with initial Query

Created on 18 Jul 2019  路  5Comments  路  Source: FormidableLabs/urql

Hi guys,
I am using urql in a page that loads a few items with a query and needs to subscribe to changes to the list. I've seen that your useSubscription hook doesn't allow for an initial query and your useQuery hook doesn't allow for a subscription.

Is there an existing method to do this? Apollo offers this as a function called subscribeToMore

Thanks!

Most helpful comment

Another alternative may be something like this:

const [queryResult] = useQuery({ /* ... */ });
const [subscriptionResult] = useSubscription(
  {
    // Only start/subscribe to subscription if the query has completed:
    pause: queryResult.fetching,
    // ...
  },
  // Add combination logic here and set default to query result:
  (prev = queryResult.data, item) => [...prev.items, item]
)

const data = subscriptionResult.data || queryResult.data;

Ultimately, this could be a good entry for our "Guides" document :+1:
But we'd also want to put some emphasis on the normalized caching, since once you introduce complex subscriptions, the normalized caching can be very beneficial.

All 5 comments

The only way I can think of is:

function() {
     const [items, setItems] = useState([])
     const [{data: initialItems}] = useQuery({query: items})
     useSubscription({ query: addedItem }, item => setItems(items => [...items, item]));
     if(initialItems && items.length < 1) setItems(initialItems)
}

Sorry for the late reply!

useSubscription has an internal state already, so you won't need to maintain your own _necessarily_, but you're right in the rest of your implementation in that you use both hooks and provide the update function to useSubscription.

But instead of having an undefined state inside useSubscription you'd use the update function to maintain the list, using the useQuery state as well for it.

There's more information on what you can do with useSubscription's second argument in the docs: https://formidable.com/open-source/urql/docs/basics/#usage-with-hooks

I've tried putting in useQuery results into the handleSubscription method but it doesn't fire on initial render (only when a socket message is received) so the data from useSubscription stays undefined. I've ended up working through an adapted version of @ivosequeros posted and combining the the responses from useQuery and useSubscription in local state.

Some docs around this would be awesome and I'd be happy to help out on them once there's a clear pattern for users to follow.

Another alternative may be something like this:

const [queryResult] = useQuery({ /* ... */ });
const [subscriptionResult] = useSubscription(
  {
    // Only start/subscribe to subscription if the query has completed:
    pause: queryResult.fetching,
    // ...
  },
  // Add combination logic here and set default to query result:
  (prev = queryResult.data, item) => [...prev.items, item]
)

const data = subscriptionResult.data || queryResult.data;

Ultimately, this could be a good entry for our "Guides" document :+1:
But we'd also want to put some emphasis on the normalized caching, since once you introduce complex subscriptions, the normalized caching can be very beneficial.

Thank you for that snippet example. Been digging URQL so far. Great job to you and the team.

Was this page helpful?
0 / 5 - 0 ratings

Related issues

TLadd picture TLadd  路  4Comments

capaj picture capaj  路  5Comments

alexraginskiy picture alexraginskiy  路  3Comments

davidhouweling picture davidhouweling  路  4Comments

kitten picture kitten  路  4Comments