3636 EventHandler ,
3737 EventSpec ,
3838 call_script ,
39+ typing_event ,
3940)
4041from reflex_base .utils .exceptions import (
4142 ComputedVarShadowsBaseVarsError ,
@@ -2268,12 +2269,6 @@ def wrapper() -> Component:
22682269class FrontendEventExceptionState (State ):
22692270 """Substate for handling frontend exceptions."""
22702271
2271- # ``__init_subclass__`` replaces the method below with an ``EventHandler``
2272- # instance on the class. Splitting via ``TYPE_CHECKING`` lets callers
2273- # (e.g. ``format_event_handler``) see the post-rewrite type.
2274- if TYPE_CHECKING :
2275- handle_frontend_exception : EventHandler
2276-
22772272 # If the frontend error message contains any of these strings, automatically reload the page.
22782273 auto_reload_on_errors : ClassVar [list [re .Pattern ]] = [
22792274 re .compile ( # Chrome/Edge
@@ -2291,68 +2286,62 @@ class FrontendEventExceptionState(State):
22912286 ),
22922287 ]
22932288
2294- if not TYPE_CHECKING :
2289+ @typing_event
2290+ def handle_frontend_exception (
2291+ self , info : str , component_stack : str
2292+ ) -> Iterator [EventSpec ]:
2293+ """Handle frontend exceptions.
22952294
2296- @event
2297- def handle_frontend_exception (
2298- self , info : str , component_stack : str
2299- ) -> Iterator [EventSpec ]:
2300- """Handle frontend exceptions.
2301-
2302- If a frontend exception handler is provided, it will be called.
2303- Otherwise, the default frontend exception handler will be called.
2304-
2305- Args:
2306- info: The exception information.
2307- component_stack: The stack trace of the component where the exception occurred.
2308-
2309- Yields:
2310- Optional auto-reload event for certain errors outside cooldown period.
2311- """
2312- # Handle automatic reload for certain errors.
2313- if type (self ).auto_reload_on_errors and any (
2314- error .search (info ) for error in type (self ).auto_reload_on_errors
2315- ):
2316- yield call_script (
2317- f"const last_reload = parseInt(window.sessionStorage.getItem('{ LAST_RELOADED_KEY } ')) || 0;"
2318- f"if (Date.now() - last_reload > { environment .REFLEX_AUTO_RELOAD_COOLDOWN_TIME_MS .get ()} )"
2319- "{"
2320- f"window.sessionStorage.setItem('{ LAST_RELOADED_KEY } ', Date.now().toString());"
2321- "window.location.reload();"
2322- "}"
2323- )
2324- prerequisites .get_and_validate_app ().app .frontend_exception_handler (
2325- Exception (info )
2295+ If a frontend exception handler is provided, it will be called.
2296+ Otherwise, the default frontend exception handler will be called.
2297+
2298+ Args:
2299+ info: The exception information.
2300+ component_stack: The stack trace of the component where the exception occurred.
2301+
2302+ Yields:
2303+ Optional auto-reload event for certain errors outside cooldown period.
2304+ """
2305+ # Handle automatic reload for certain errors.
2306+ if type (self ).auto_reload_on_errors and any (
2307+ error .search (info ) for error in type (self ).auto_reload_on_errors
2308+ ):
2309+ yield call_script (
2310+ f"const last_reload = parseInt(window.sessionStorage.getItem('{ LAST_RELOADED_KEY } ')) || 0;"
2311+ f"if (Date.now() - last_reload > { environment .REFLEX_AUTO_RELOAD_COOLDOWN_TIME_MS .get ()} )"
2312+ "{"
2313+ f"window.sessionStorage.setItem('{ LAST_RELOADED_KEY } ', Date.now().toString());"
2314+ "window.location.reload();"
2315+ "}"
23262316 )
2317+ prerequisites .get_and_validate_app ().app .frontend_exception_handler (
2318+ Exception (info )
2319+ )
23272320
23282321
23292322class UpdateVarsInternalState (State ):
23302323 """Substate for handling internal state var updates."""
23312324
2332- # See ``FrontendEventExceptionState`` for why this is split.
2333- if TYPE_CHECKING :
2334- update_vars_internal : EventHandler
2335- else :
2325+ @typing_event
2326+ async def update_vars_internal (self , vars : dict [str , Any ]) -> None :
2327+ """Apply updates to fully qualified state vars.
23362328
2337- async def update_vars_internal ( self , vars : dict [ str , Any ]) -> None :
2338- """Apply updates to fully qualified state vars .
2329+ The keys in ` vars` should be in the form of `{state.get_full_name()}.{var_name}`,
2330+ and each value will be set on the appropriate substate instance .
23392331
2340- The keys in `vars` should be in the form of `{state.get_full_name()}.{var_name}`,
2341- and each value will be set on the appropriate substate instance .
2332+ This function is primarily used to apply cookie and local storage
2333+ updates from the frontend to the appropriate substate.
23422334
2343- This function is primarily used to apply cookie and local storage
2344- updates from the frontend to the appropriate substate.
2345-
2346- Args:
2347- vars: The fully qualified vars and values to update.
2348- """
2349- for var , value in vars .items ():
2350- state_name , _ , var_name = var .rpartition ("." )
2351- var_name = var_name .removesuffix (FIELD_MARKER )
2352- var_state_cls = State .get_class_substate (state_name )
2353- if var_state_cls ._is_client_storage (var_name ):
2354- var_state = await self .get_state (var_state_cls )
2355- setattr (var_state , var_name , value )
2335+ Args:
2336+ vars: The fully qualified vars and values to update.
2337+ """
2338+ for var , value in vars .items ():
2339+ state_name , _ , var_name = var .rpartition ("." )
2340+ var_name = var_name .removesuffix (FIELD_MARKER )
2341+ var_state_cls = State .get_class_substate (state_name )
2342+ if var_state_cls ._is_client_storage (var_name ):
2343+ var_state = await self .get_state (var_state_cls )
2344+ setattr (var_state , var_name , value )
23562345
23572346
23582347class OnLoadInternalState (State ):
@@ -2361,47 +2350,42 @@ class OnLoadInternalState(State):
23612350 This is a separate substate to avoid deserializing the entire state tree for every page navigation.
23622351 """
23632352
2364- # See ``FrontendEventExceptionState`` for why this is split.
2365- if TYPE_CHECKING :
2366- on_load_internal : EventHandler
2367-
23682353 # Cannot properly annotate this as `App` due to circular import issues.
23692354 _app_ref : ClassVar [Any ] = None
23702355
2371- if not TYPE_CHECKING :
2356+ @typing_event
2357+ def on_load_internal (self ) -> list [Event | EventSpec | event .EventCallback ] | None :
2358+ """Queue on_load handlers for the current page.
2359+
2360+ Returns:
2361+ The list of events to queue for on load handling.
2362+
2363+ Raises:
2364+ TypeError: If the app reference is not of type App.
2365+ """
2366+ from reflex .app import App
23722367
2373- def on_load_internal (
2374- self ,
2375- ) -> list [Event | EventSpec | event .EventCallback ] | None :
2376- """Queue on_load handlers for the current page.
2377-
2378- Returns:
2379- The list of events to queue for on load handling.
2380-
2381- Raises:
2382- TypeError: If the app reference is not of type App.
2383- """
2384- from reflex .app import App
2385-
2386- app = type (self )._app_ref or prerequisites .get_and_validate_app ().app
2387- if not isinstance (app , App ):
2388- msg = f"Expected app to be of type { App .__name__ } , got { type (app ).__name__ } ."
2389- raise TypeError (msg )
2390- # Cache the app reference for subsequent calls.
2391- if type (self )._app_ref is None :
2392- type(self )._app_ref = app
2393- load_events = app .get_load_events (self .router .url .path )
2394- if not load_events :
2395- self .is_hydrated = True
2396- return None # Fast path for navigation with no on_load events defined.
2397- self .is_hydrated = False
2398- return [
2399- * Event .from_event_type (
2400- load_events ,
2401- router_data = self .router_data ,
2402- ),
2403- State .set_is_hydrated (True ),
2404- ]
2368+ app = type (self )._app_ref or prerequisites .get_and_validate_app ().app
2369+ if not isinstance (app , App ):
2370+ msg = (
2371+ f"Expected app to be of type { App .__name__ } , got { type (app ).__name__ } ."
2372+ )
2373+ raise TypeError (msg )
2374+ # Cache the app reference for subsequent calls.
2375+ if type (self )._app_ref is None :
2376+ type(self )._app_ref = app
2377+ load_events = app .get_load_events (self .router .url .path )
2378+ if not load_events :
2379+ self .is_hydrated = True
2380+ return None # Fast path for navigation with no on_load events defined.
2381+ self .is_hydrated = False
2382+ return [
2383+ * Event .from_event_type (
2384+ load_events ,
2385+ router_data = self .router_data ,
2386+ ),
2387+ State .set_is_hydrated (True ),
2388+ ]
24052389
24062390
24072391class ComponentState (State , mixin = True ):
0 commit comments