From da85da1ab319de236d2bfb1fb324fea6afe6e969 Mon Sep 17 00:00:00 2001 From: Mikael Grankvist Date: Tue, 12 Nov 2024 08:56:56 +0200 Subject: [PATCH 1/2] fix: multiple fast navigate calls Fix issue where a slow connection and fast `navigate` calls throws exception due to faulty blocker state change. Fixes #20404 --- .../resources/com/vaadin/flow/server/frontend/Flow.tsx | 10 ++++++++++ 1 file changed, 10 insertions(+) diff --git a/flow-server/src/main/resources/com/vaadin/flow/server/frontend/Flow.tsx b/flow-server/src/main/resources/com/vaadin/flow/server/frontend/Flow.tsx index e3e571470c3..4066b940d2a 100644 --- a/flow-server/src/main/resources/com/vaadin/flow/server/frontend/Flow.tsx +++ b/flow-server/src/main/resources/com/vaadin/flow/server/frontend/Flow.tsx @@ -273,6 +273,7 @@ function Flow() { }); const location = useLocation(); const navigated = useRef(false); + const blockerHandled = useRef(false); const fromAnchor = useRef(false); const containerRef = useRef(undefined); const roundTrip = useRef | undefined>(undefined); @@ -360,9 +361,18 @@ function Flow() { }, []); useEffect(() => { + if(blockerHandled.current) { + // blocker is handled and no new navigation is accepted. + // This will cancel multiple navigate calls, but not multiple calls + // from the server as those are queued. #20404 + return; + } if (blocker.state === 'blocked') { + blockerHandled.current = true; let blockingPromise: any; roundTrip.current = new Promise((resolve,reject) => blockingPromise = {resolve:resolve,reject:reject}); + // Release blocker handling after promise is fulfilled + roundTrip.current.then(() => blockerHandled.current = false, () => blockerHandled.current = false); // Proceed to the blocked location, unless the navigation originates from a click on a link. // In that case continue with function execution and perform a server round-trip From c849bf2e625c7c5d1f7b3eeb6609d3196ee5fcfe Mon Sep 17 00:00:00 2001 From: Mikael Grankvist Date: Mon, 18 Nov 2024 11:52:45 +0200 Subject: [PATCH 2/2] Queue new navigations during ongoing navigation. --- .../com/vaadin/flow/server/frontend/Flow.tsx | 13 +++++++------ 1 file changed, 7 insertions(+), 6 deletions(-) diff --git a/flow-server/src/main/resources/com/vaadin/flow/server/frontend/Flow.tsx b/flow-server/src/main/resources/com/vaadin/flow/server/frontend/Flow.tsx index 4066b940d2a..d9814a8fa84 100644 --- a/flow-server/src/main/resources/com/vaadin/flow/server/frontend/Flow.tsx +++ b/flow-server/src/main/resources/com/vaadin/flow/server/frontend/Flow.tsx @@ -361,13 +361,14 @@ function Flow() { }, []); useEffect(() => { - if(blockerHandled.current) { - // blocker is handled and no new navigation is accepted. - // This will cancel multiple navigate calls, but not multiple calls - // from the server as those are queued. #20404 - return; - } if (blocker.state === 'blocked') { + if(blockerHandled.current) { + // Blocker is handled and the new navigation + // gets queued to be executed after the current handling ends. + const {pathname, state} = blocker.location; + queuedNavigate(pathname, true, { state: state, replace: true }); + return; + } blockerHandled.current = true; let blockingPromise: any; roundTrip.current = new Promise((resolve,reject) => blockingPromise = {resolve:resolve,reject:reject});