Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
38 commits
Select commit Hold shift + click to select a range
608f448
Split router into per-field base vars; gather static router data at c…
claude Aug 28, 2026
c42e20c
Merge remote-tracking branch 'origin/main' into claude/router-vars-re…
claude Sep 8, 2026
752f403
Add news fragments; stop router dep tests leaking class-level registr…
claude Sep 8, 2026
a2af873
Add reflex-base news fragment for the router var split
claude Sep 8, 2026
bfb89fa
Rebuild the session var from router_data when linking a token to a sid
claude Sep 8, 2026
605b681
Assign a router var only when its rebuilt value differs
claude Sep 8, 2026
d5c82f4
Keep the new on_event tests from leaking tokens into a shared redis
claude Sep 8, 2026
c7a08e5
Address review findings on the router var split
claude Sep 8, 2026
c7e8c18
Record the connecting token in router_data when linking a sid
claude Sep 8, 2026
05372dd
Carry omitted router_data keys forward when rebuilding the router vars
claude Sep 8, 2026
14d7662
Give the serialized router keys a single source of truth
claude Sep 8, 2026
9c270ca
Do not store merged router_data when it changes nothing
claude Sep 8, 2026
4dd07c9
List `router` as a var so substates inherit the switchboard
claude Sep 9, 2026
7551260
Correct the stale get_skip_vars comment for `router`
claude Sep 9, 2026
a6a79a7
Merge upstream/main into router-vars-refactor
FarhanAliRaza Sep 11, 2026
5de5328
Track every field a composite var reads in VarData.field_names
claude Sep 15, 2026
c9ea01c
Prefix the per-field router vars with rx_
claude Sep 15, 2026
1cea0bc
Merge remote-tracking branch 'origin/main' into codex/pr-7068
masenf Sep 16, 2026
6b2afe7
Fix router name collisions and composed-var dependencies
masenf Sep 16, 2026
db3caad
Point the router deps deprecation at the Var form
claude Sep 16, 2026
153b1ef
Hoist the reserved router name check out of __init_subclass__
claude Sep 16, 2026
2291f15
Merge remote-tracking branch 'origin/main' into codex/pr-7068
masenf Sep 16, 2026
2cc9436
Merge remote-tracking branch 'origin/main' into codex/pr-7068
masenf Sep 17, 2026
13bba36
Merge remote-tracking branch 'origin/main' into codex/pr-7068
masenf Sep 17, 2026
2d76032
Share the empty router defaults across states
claude Sep 17, 2026
8cc79e5
Make ReflexURL reject attribute assignment
claude Sep 17, 2026
c67a9bc
Group VarData field dependencies by owning state
claude Sep 17, 2026
8b4a59d
Address review of the VarData field dependency grouping
claude Sep 17, 2026
1d93bfe
Drop the field_names accessor from VarData
claude Sep 17, 2026
22ef10c
Name the legacy router pickle key and cover the drop
claude Sep 17, 2026
7cb4c6a
Merge origin/main and drop the router reserved-name check
claude Sep 17, 2026
847c97f
Merge remote-tracking branch 'origin/main' into claude/router-vars-re…
claude Sep 18, 2026
3be9b1e
Persist the router URL as the URL, not as its parsed pieces
claude Sep 18, 2026
c446e4b
Merge remote-tracking branch 'origin/main' into codex/pr-7068
masenf Sep 18, 2026
ef47368
Resolve get_var_value(State.router) and name the deprecated var
claude Sep 18, 2026
bc62484
Merge remote-tracking branch 'origin/main' into claude/router-vars-re…
claude Sep 18, 2026
f07fc21
Build the merged field dependencies in one pass
claude Sep 18, 2026
92ee46f
Merge remote-tracking branch 'origin/main' into claude/router-vars-re…
claude Sep 18, 2026
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
1 change: 1 addition & 0 deletions news/7068.breaking.md
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
The root state gained five base vars holding the router data: `rx_router_session`, `rx_router_headers`, `rx_router_page`, `rx_router_url` and `rx_router_route_id`. A substate that declares one of these names now raises `BaseVarShadowsInheritedVarError`, the same error any other shadowed inherited var raises, and must rename its field. `State.router` itself is unchanged.
1 change: 1 addition & 0 deletions news/7068.deprecation.md
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
Declaring a computed var dependency on the `router` var (`deps=["router"]`) is deprecated; depend on the router Var instead, e.g. `deps=[State.router.url]` for a single field or `deps=[State.router]` to keep tracking all of them.
3 changes: 3 additions & 0 deletions news/7068.performance.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
Store router data in separate base vars (session, headers, page, url, route_id) so a navigation delta only re-sends the fields that changed instead of the whole router, and gather the connection-scoped router data (headers, client IP, session id) once at connect time rather than on every event. `State.router` is unchanged for app code.

The page URL is also persisted as the URL itself rather than as its parsed pieces: `ReflexURL` and `URLData` re-split on the way out of the state store instead of writing scheme, netloc, origin, path, query, query parameters and fragment alongside the href on every state write.
1 change: 1 addition & 0 deletions packages/reflex-base/news/7068.feature.md
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
`VarData` now tracks every state field a var is built from in `field_dependencies`, a mapping of state name to that state's field names, unioned and deduped as vars merge. A computed var depending on a composite var (`deps=[SomeState.composite]`) is now invalidated when any of its underlying fields changes — including fields belonging to a different state, which previously went untracked. `state` and `field_name` still report the first state and its first field, so existing readers are unaffected; read `field_dependencies` when you need every state a var reaches.
1 change: 1 addition & 0 deletions packages/reflex-base/news/7068.performance.md
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
The event processor now refreshes only the router vars whose backing `router_data` keys actually changed, so a navigation no longer rebuilds and re-sends the connection-scoped session and header data. `ROUTER_VARS` names the per-field router vars that replaced the single `router` var on the root state.
12 changes: 12 additions & 0 deletions packages/reflex-base/src/reflex_base/constants/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -60,6 +60,12 @@
ROUTER,
ROUTER_DATA,
ROUTER_DATA_INCLUDE,
ROUTER_HEADERS,
ROUTER_PAGE,
ROUTER_ROUTE_ID,
ROUTER_SESSION,
ROUTER_URL,
ROUTER_VARS,
DefaultPage,
Page404,
RouteArgType,
Expand All @@ -86,6 +92,12 @@
"ROUTER",
"ROUTER_DATA",
"ROUTER_DATA_INCLUDE",
"ROUTER_HEADERS",
"ROUTER_PAGE",
"ROUTER_ROUTE_ID",
"ROUTER_SESSION",
"ROUTER_URL",
"ROUTER_VARS",
"ROUTE_NOT_FOUND",
"SESSION_STORAGE",
"SETTER_PREFIX",
Expand Down
22 changes: 21 additions & 1 deletion packages/reflex-base/src/reflex_base/constants/route.py
Original file line number Diff line number Diff line change
Expand Up @@ -11,10 +11,30 @@ class RouteArgType(SimpleNamespace):
LIST = "arg_list"


# the name of the backend var containing path and client information
# the name of the state attribute exposing path and client information
ROUTER = "router"
ROUTER_DATA = "router_data"

# The names of the per-field base vars holding router data on the root state.
# Session and headers are constant for the lifetime of a websocket connection,
# while page, url, and route_id change on every navigation; keeping them in
# separate vars means a navigation delta only re-sends the navigation fields.
# The `rx_` prefix keeps them from colliding with a field an app already
# defines; `router` itself stays unprefixed as the public switchboard.
ROUTER_SESSION = "rx_router_session"
ROUTER_HEADERS = "rx_router_headers"
ROUTER_PAGE = "rx_router_page"
ROUTER_URL = "rx_router_url"
ROUTER_ROUTE_ID = "rx_router_route_id"

ROUTER_VARS = (
ROUTER_SESSION,
ROUTER_HEADERS,
ROUTER_PAGE,
ROUTER_URL,
ROUTER_ROUTE_ID,
)


class RouteVar(SimpleNamespace):
"""Names of variables used in the router_data dict stored in State."""
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,6 @@
from time import perf_counter
from typing import TYPE_CHECKING, Any

from reflex.istate.data import RouterData
from reflex.istate.manager.token import BaseStateToken
from reflex.istate.proxy import StateProxy
from reflex.utils import types
Expand Down Expand Up @@ -431,12 +430,20 @@ async def _execute_event(
)

# re-assign only when the value is set and different
if router_data and state.router_data != router_data:
# assignment will recurse into substates and force recalculation of
# dependent ComputedVar (dynamic route variables)
state.router_data = router_data
if state.router != (router := RouterData.from_router_data(router_data)):
state.router = router
if (
router_data
and (previous_router_data := state.router_data) != router_data
):
# only the router vars whose backing keys changed are rebuilt
# and re-sent; session/headers stay put across navigations.
merged_router_data = state._update_router_vars(
router_data, previous_router_data
)
# Store what it merged, not the payload, so a partial payload
# does not drop the keys it omits. Only on a real change: the
# assignment dirties router_data and marks the state touched.
if merged_router_data != previous_router_data:
Comment thread
cubic-dev-ai[bot] marked this conversation as resolved.
state.router_data = merged_router_data

# Preprocess the event.
if (
Expand Down
Loading
Loading