react-query-subscription
react-query-subscription copied to clipboard
Hook based on React Query for managing, caching and syncing observables in React
React Query useSubscription
hook
Background
While React Query is very feature rich, it misses one thing - support for streams, event emitters, WebSockets etc. This library leverages React Query's useQuery
to provide useSubscription
hook for subscribing to real-time data.
General enough solution
React Query useQuery
's query function is any function which returns a Promise. Similarly, useSubscription
's subscription function is any function which returns an Observable.
Installation
NPM
npm install react-query-subscription react react-query@3 rxjs@7
or
yarn add react-query-subscription react react-query@3 rxjs@7
Use cases
Please see examples.
Subscribe to WebSocket
TODO
Subscribe to Event source
import { QueryClientProvider, QueryClient } from 'react-query';
import { ReactQueryDevtools } from 'react-query/devtools';
import { useSubscription } from 'react-query-subscription';
import { eventSource$ } from 'rx-event-source';
const queryClient = new QueryClient();
function App() {
return (
<QueryClientProvider client={queryClient}>
<SseExample />
<ReactQueryDevtools initialIsOpen={false} />
</QueryClientProvider>
);
}
function SseExample() {
const { data, isLoading, isError, error } = useSubscription(
'some-key',
// @see https://kaciakmaciak.github.io/rx-event-source/modules.html#eventSource_
() => eventSource$('/api/v1/sse'),
{
// options
}
);
if (isLoading) {
return <div>Loading...</div>;
}
if (isError) {
return (
<div role="alert">
{error?.message || 'Unknown error'}
</div>
);
}
return <div>Data: {JSON.stringify(data)}</div>;
}
See rx-event-source
docs.
GraphQL subscription using graphql-ws
import { QueryClientProvider, QueryClient } from 'react-query';
import { ReactQueryDevtools } from 'react-query/devtools';
import { useSubscription } from 'react-query-subscription';
import { Observable } from 'rxjs';
import { createClient } from 'graphql-ws';
import type { Client, SubscribePayload } from 'graphql-ws';
const queryClient = new QueryClient();
function App() {
return (
<QueryClientProvider client={queryClient}>
<GraphQlWsExample postId="abc123" />
<ReactQueryDevtools initialIsOpen={false} />
</QueryClientProvider>
);
}
const client = createClient({ url: 'wss://example.com/graphql' });
/**
* @see https://github.com/enisdenjo/graphql-ws#observable
*/
export function fromWsClientSubscription<TData = Record<string, unknown>>(
client: Client,
payload: SubscribePayload
) {
return new Observable<TData | null>((observer) =>
client.subscribe<TData>(payload, {
next: (data) => observer.next(data.data),
error: (err) => observer.error(err),
complete: () => observer.complete(),
})
);
}
interface Props {
postId: string;
}
interface Comment {
id: string;
content: string;
}
function GraphQlWsExample({ postId }: Props) {
const { data, isLoading, isError, error } = useSubscription(
'some-key',
() => fromWsClientSubscription<{ comments: Array<Comment> }>({
query: `
subscription Comments($postId: ID!) {
comments(postId: $postId) {
id
content
}
}
`,
variables: {
postId,
},
}),
{
// options
}
);
if (isLoading) {
return <div>Loading...</div>;
}
if (isError) {
return (
<div role="alert">
{error?.message || 'Unknown error'}
</div>
);
}
return <div>Data: {JSON.stringify(data?.comments)}</div>;
}
Contributors ✨
Thanks goes to these wonderful people (emoji key):
Katarina Anton 💻 🤔 🚧 ⚠️ 🔧 🚇 |
Jacob Cable 💻 🤔 |
This project follows the all-contributors specification. Contributions of any kind welcome!