Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion reflex/.templates/web/utils/client_side_routing.js
Original file line number Diff line number Diff line change
Expand Up @@ -25,7 +25,7 @@ export const useClientSideRouting = () => {
const search = window.location.search;

// Use navigate instead of replace
navigate(path + search, { replace: true })
navigate(path + search, { replace: true, state: { fromNotFound: true } })
.then(() => {
// Check if we're still on a NotFound route
// Note: This depends on how your routes are set up
Expand Down
53 changes: 32 additions & 21 deletions reflex/.templates/web/utils/state.js
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@ import JSON5 from "json5";
import env from "$/env.json";
import reflexEnvironment from "$/reflex.json";
import Cookies from "universal-cookie";
import { useEffect, useRef, useState } from "react";
import { useCallback, useEffect, useRef, useState } from "react";
import {
useLocation,
useNavigate,
Expand Down Expand Up @@ -851,7 +851,7 @@ export const useEventLoop = (
}, [paramsR]);

// Function to add new events to the event queue.
const addEvents = (events, args, event_actions) => {
const addEvents = useCallback((events, args, event_actions) => {
const _events = events.filter((e) => e !== undefined && e !== null);

if (!(args instanceof Array)) {
Expand Down Expand Up @@ -894,7 +894,7 @@ export const useEventLoop = (
} else {
queueEvents(_events, socket, false, navigate, () => params.current);
}
};
}, []);

const sentHydrate = useRef(false); // Avoid double-hydrate due to React strict-mode
useEffect(() => {
Expand Down Expand Up @@ -1020,31 +1020,42 @@ export const useEventLoop = (
return () => window.removeEventListener("storage", handleStorage);
});

const handleNavigationEvents = useRef(false);
// Route after the initial page hydration
useEffect(() => {
// The first time this effect runs is initial load, so don't handle
// any navigation events.
if (!handleNavigationEvents.current) {
handleNavigationEvents.current = true;
return;
}
if (location.state?.fromNotFound) {
// If the redirect is from a 404 page, we skip onLoadInternalEvent,
// since it was already run when the 404 page was first rendered.
return;
}
// This will run when the location changes
if (
location.pathname + location.search + location.hash !==
prevLocationRef.current.pathname +
prevLocationRef.current.search +
prevLocationRef.current.hash
location.pathname + location.search ===
prevLocationRef.current.pathname + prevLocationRef.current.search
) {
// Equivalent to routeChangeStart - runs when navigation begins
const change_start = () => {
const main_state_dispatch = dispatch["reflex___state____state"];
if (main_state_dispatch !== undefined) {
main_state_dispatch({ is_hydrated_rx_state_: false });
}
};
change_start();

// Equivalent to routeChangeComplete - runs after navigation completes
const change_complete = () => addEvents(onLoadInternalEvent());
change_complete();
if (location.hash) {
// If the hash is the same, we don't need to do anything.
return;
}
}

// Update the ref
prevLocationRef.current = location;
// Equivalent to routeChangeStart - runs when navigation begins
const main_state_dispatch = dispatch["reflex___state____state"];
if (main_state_dispatch !== undefined) {
main_state_dispatch({ is_hydrated_rx_state_: false });
}

// Equivalent to routeChangeComplete - runs after navigation completes
addEvents(onLoadInternalEvent());

// Update the ref
prevLocationRef.current = location;
}, [location, dispatch, onLoadInternalEvent, addEvents]);

return [addEvents, connectErrors];
Expand Down
6 changes: 6 additions & 0 deletions tests/integration/test_dynamic_routes.py
Original file line number Diff line number Diff line change
Expand Up @@ -386,6 +386,12 @@ async def test_on_load_navigate_non_dynamic(
assert urlsplit(driver.current_url).path.removesuffix("/") == "/static/x"
await poll_for_order(["/static/x-no page id", "/static/x-no page id"])

for _ in range(3):
link = driver.find_element(By.ID, "link_page_x")
link.click()
assert urlsplit(driver.current_url).path.removesuffix("/") == "/static/x"
await poll_for_order(["/static/x-no page id"] * 5)
Comment thread
adhami3310 marked this conversation as resolved.


@pytest.mark.asyncio
async def test_render_dynamic_arg(
Expand Down
Loading