-
-
Notifications
You must be signed in to change notification settings - Fork 1.2k
Description
What I’m doing
I’m building a feature where the user can “pop out” a panel into a new browser window.
I create the new window and render React content into it via createPortal:
const [container, setContainer] = useState(null);
const [panelWindow, setPanelWindow] = useState(null);
useEffect(() => {
const popup = window.open("", "_blank", "width=600,height=800");
if (!popup) return;
const el = popup.document.createElement("div");
popup.document.body.appendChild(el);
setPanelWindow(popup);
setContainer(el);
return () => popup.close();
}, []);
if (!container || !panelWindow) return null;
//wrapped by the same Redux <Provider>
return createPortal(
<Panel />,
container
);
The Panel contains RTK Query hooks (useGetXQuery, useMutation, etc.) that subscribe to data.
What works
• If I use vanilla Redux slices (dispatch / useSelector), the panel updates correctly in the new window.
• If I use axios + useState, it also works fine.
• RTK Query mutations (usePatchSomethingMutation) dispatch correctly and update the cache.
• Redux DevTools shows the cache entry as updated and fulfilled.
What breaks
• Components rendered into the new window with RTK Query hooks (useGetXQuery) do not re-render when the cache updates.
• debugValue inside the hook shows the updated data (e.g. 39 rows), but data / currentData in the component remain stale (e.g. 38 rows).
• If I force any re-render (resizing, dispatching a dummy action, or making the main window visible by even a single pixel), the panel updates immediately with the correct data.
• This only happens when the new window is maximized; if the main window is visible even slightly or the popup is resized, the panel updates immediately.
Why I think this is happening
• RTK Query hooks rely on useSyncExternalStore subscriptions.
• useSyncExternalStore seems tied to the main document visibility/focus for scheduling updates.
• Since the component tree is portaled into a different window.document, subscriptions don’t flush updates until the main document becomes visible again.
• Plain Redux works because reducers just update state immediately, without visibility checks.
Steps to reproduce
- Render an RTK Query-enabled component into a new window using createPortal.
- Maximize the new window.
- Trigger a mutation that updates the cached query data.
- Observe: DevTools shows the cache updated, but the new window UI does not.
- Force a re-render (resize window, dispatch dummy action, show main document). Now the new window updates.
Expected behavior
RTK Query subscriptions should notify and re-render components in any window as long as they are part of the same React tree + Redux store. Visibility of the original document should not matter.
Workarounds tried
• refetch() → does not help.
• Dispatching a dummy action → works, but hacky.
• Separate React root in popup with → still broken for RTK Query (but plain Redux works fine).
Environment
• React 19.1.0
• Redux Toolkit 2.9.0
• Browser: Chrome (latest), also reproduced in Firefox
Here is a minimal reproducible example: https://codesandbox.io/p/sandbox/zpqhcz