I want to synchronize a SPA React application for all users (multiple tabs, multiple users). I wrote a simple reactive hook that listens for specific socket IO messages and updates a state variable based on the message called useGetAllEmployeesQuery
:
import { useEffect, useState } from 'react' export function useRefetchOnMessage (messageType) { const [needRefetch, setNeedRefetch] = useState() if (!window.io.socket) { return } function handleMessage (e) { setNeedRefetch(Date.now()) } useEffect(() => { window.io.socket.on(messageType, handleMessage) return () => { window.io.socket.off(messageType, handleMessage) } }, []) return needRefetch }
When this event is dispatched, I simply call the RTK refetch()
method.
const employees = useGetAllEmployeesQuery(officeId) const needRefreshEmployees = useRefetchOnMessage('employees changed') useEffect(() => { if (!needRefreshEmployees) return employees.refetch() }, [needRefreshEmployees])
So we need to call it everywhere in the application, let's say we have 5 components that use employee query, we need to call refetch
in all components. Many queries only need to be run once to run. (Invalid once)
Is it possible to subscribe to any type of such events in a Redux RTK query configuration?
P粉7617185462024-01-30 00:12:10
You can trigger a subscribed query by invalidating the tag to re query it.
See invalidateTags: a Redux action creator that can be used to manually invalidate 's cache tags and automatically re-fetch .
Assuming that the getAllEmployees
endpoint provides a tag, such as "employees"
, you can schedule an action to invalidate the tag and trigger the useGetAllEmployeesQuery
hook to re retrieve data.
const api = createApi({ ... endpoints: builder => ({ ... getAllEmployees: builder.query({ query: ......, ... providesTags: ["employees"], }), ... }), });
import { useEffect } from 'react'; import { useDispatch } from 'react-redux'; import api from '../path/to/apiSlice'; export function useRefetchOnMessage (messageType = "", tags = []) { const dispatch = useDispatch(); useEffect(() => { const handleMessage = () => { dispatch(api.util.invalidateTags(tags)); }; window.io?.socket?.on(messageType, handleMessage); return () => { window.io?.socket?.off(messageType, handleMessage); } }, [messageType, tags]); }
The UI code simply calls the hook, passing the "employees"
token to the useRefetchOnMessage
hook.
const employees = useGetAllEmployeesQuery(officeId); useRefetchOnMessage('employees changed', ["employees"]);