Search code examples
javascriptreduxredux-toolkitrtk-query

How to create streaming endpoint without initial data fetch in redux toolkit


I need to use a streaming connection in redux-toolkit.

The example in docs is implemented using an initial fetch to retrieve the previous message history:

export const api = createApi({
  baseQuery: fetchBaseQuery({ baseUrl: '/' }),
  endpoints: (build) => ({
    getMessages: build.query<Message[], Channel>({
      // retrieve initial data
      query: (channel) => `messages/${channel}`,
      async onCacheEntryAdded(
        arg,
        { updateCachedData, cacheDataLoaded, cacheEntryRemoved }
      ) {
        // create a websocket connection when the cache subscription starts
        const ws = new WebSocket('ws://localhost:8080')
        try {
          // wait for the initial query to resolve before proceeding
          await cacheDataLoaded

          // when data is received from the socket connection to the server,
          // if it is a message and for the appropriate channel,
          // update our query result with the received message
          const listener = (event: MessageEvent) => {
            const data = JSON.parse(event.data)
            if (!isMessage(data) || data.channel !== arg) return

            updateCachedData((draft) => {
              draft.push(data)
            })
          }

          ws.addEventListener('message', listener)
        } catch {
          // no-op in case `cacheEntryRemoved` resolves before `cacheDataLoaded`,
          // in which case `cacheDataLoaded` will throw
        }
        // cacheEntryRemoved will resolve when the cache subscription is no longer active
        await cacheEntryRemoved
        // perform cleanup steps once the `cacheEntryRemoved` promise resolves
        ws.close()
      },
    }),
  }),
})

export const { useGetMessagesQuery } = api

My endpoint only admits streaming updates, but doesnt have an initial data response. How can I implement the streaming endpoint without the initial fetch?

What I have tried:

  • Removing the query property.
  • Returning undefined in the responseHandler of query.

Solution

  • One option here would be to use a queryFn that returns an initial empty data value (and thus doesn't make an API call to the server), such as:

      streamSomeData: build.query({
        queryFn: async () => ({data: null}),
        onCacheEntryAdded: async (
            arg,
            { updateCachedData, cacheDataLoaded, cacheEntryRemoved }
          ) => {
            // streaming logic here
          }
      })