File tree Expand file tree Collapse file tree 1 file changed +18
-0
lines changed
Expand file tree Collapse file tree 1 file changed +18
-0
lines changed Original file line number Diff line number Diff line change @@ -148,6 +148,24 @@ export const useOverlayController = () => {
148148 return useStateStore ( overlayStore , selector ) ;
149149} ;
150150
151+ /**
152+ * NOTE:
153+ * Do not swap this back to `useStateStore(closingPortalLayoutsStore, selector)`.
154+ *
155+ * Why this is special:
156+ * - `layouts` is a dynamic-key map (hosts are added/removed at runtime)
157+ * - We only need React updates when the key set changes (add/remove/reset)
158+ * - Per-layout movement is already on UI thread via `entry.layout.value`
159+ *
160+ * Why `useStateStore` is unsafe here:
161+ * - Both `stream-chat`'s `subscribeWithSelector` and our `useStateStore` snapshot
162+ * comparator use an asymmetric key comparison (they iterate previous keys only)
163+ * - That means `{}` -> `{ newHost: entry }` can be treated as "no change"
164+ * - When that happens, overlay slots never mount even though registration has run
165+ *
166+ * `useSyncExternalStore` with raw store subscription avoids that selector compare path,
167+ * so add/remove of hosts is always treated as observable.
168+ */
151169export const useClosingPortalLayouts = ( ) => {
152170 const subscribe = useCallback (
153171 ( listener : ( ) => void ) =>
You can’t perform that action at this time.
0 commit comments