4242from reflex .environment import PerformanceMode , environment
4343from reflex .event import (
4444 BACKGROUND_TASK_MARKER ,
45+ EVENT_ID_MARKER ,
4546 Event ,
4647 EventHandler ,
4748 EventSpec ,
@@ -429,6 +430,9 @@ class BaseState(EvenMoreBasicBaseState):
429430 # The explicit state ID for minification (None = use full name).
430431 _state_id : ClassVar [int | None ] = None
431432
433+ # Per-class registry mapping event_id -> event handler name for minification.
434+ _event_id_to_name : ClassVar [builtins .dict [int , str ]] = {}
435+
432436 # The parent state.
433437 parent_state : BaseState | None = field (default = None , is_var = False )
434438
@@ -711,6 +715,36 @@ def __init_subclass__(
711715 cls .event_handlers [name ] = handler
712716 setattr (cls , name , handler )
713717
718+ # Build event_id registry and validate uniqueness within this state class
719+ cls ._event_id_to_name = {}
720+ missing_event_ids : list [str ] = []
721+ for name , fn in events .items ():
722+ event_id = getattr (fn , EVENT_ID_MARKER , None )
723+ if event_id is not None :
724+ if event_id in cls ._event_id_to_name :
725+ existing_name = cls ._event_id_to_name [event_id ]
726+ msg = (
727+ f"Duplicate event_id={ event_id } in state '{ cls .__name__ } ': "
728+ f"handlers '{ existing_name } ' and '{ name } ' cannot share the same event_id."
729+ )
730+ raise StateValueError (msg )
731+ cls ._event_id_to_name [event_id ] = name
732+ else :
733+ missing_event_ids .append (name )
734+
735+ # In ENFORCE mode, all event handlers must have event_id
736+ from reflex .environment import MinifyMode
737+
738+ if (
739+ environment .REFLEX_MINIFY_EVENTS .get () == MinifyMode .ENFORCE
740+ and missing_event_ids
741+ ):
742+ msg = (
743+ f"State '{ cls .__name__ } ' in ENFORCE mode: event handlers "
744+ f"{ missing_event_ids } are missing required event_id."
745+ )
746+ raise StateValueError (msg )
747+
714748 # Initialize per-class var dependency tracking.
715749 cls ._var_dependencies = {}
716750 cls ._init_var_dependency_dicts ()
@@ -753,6 +787,10 @@ def _copy_fn(fn: Callable) -> Callable:
753787 newfn .__annotations__ = fn .__annotations__
754788 if mark := getattr (fn , BACKGROUND_TASK_MARKER , None ):
755789 setattr (newfn , BACKGROUND_TASK_MARKER , mark )
790+ # Preserve event_id for minification
791+ event_id = getattr (fn , EVENT_ID_MARKER , None )
792+ if event_id is not None :
793+ object .__setattr__ (newfn , EVENT_ID_MARKER , event_id )
756794 return newfn
757795
758796 @staticmethod
@@ -1059,22 +1097,22 @@ def get_name(cls) -> str:
10591097 Raises:
10601098 StateValueError: If ENFORCE mode is set and state_id is missing.
10611099 """
1062- from reflex .environment import StateMinifyMode
1100+ from reflex .environment import MinifyMode
10631101 from reflex .utils .exceptions import StateValueError
10641102
10651103 module = cls .__module__ .replace ("." , "___" )
10661104 full_name = format .to_snake_case (f"{ module } ___{ cls .__name__ } " )
10671105
10681106 minify_mode = environment .REFLEX_MINIFY_STATES .get ()
10691107
1070- if minify_mode == StateMinifyMode .DISABLED :
1108+ if minify_mode == MinifyMode .DISABLED :
10711109 return full_name
10721110
10731111 if cls ._state_id is not None :
10741112 return _int_to_minified_name (cls ._state_id )
10751113
10761114 # state_id not set
1077- if minify_mode == StateMinifyMode .ENFORCE :
1115+ if minify_mode == MinifyMode .ENFORCE :
10781116 msg = (
10791117 f"State '{ cls .__module__ } .{ cls .__name__ } ' is missing required state_id. "
10801118 f"Add state_id parameter: class { cls .__name__ } (rx.State, state_id=N)"
@@ -1797,6 +1835,25 @@ async def get_var_value(self, var: Var[VAR_TYPE]) -> VAR_TYPE:
17971835 )
17981836 return getattr (other_state , var_data .field_name )
17991837
1838+ @classmethod
1839+ def _get_original_event_name (cls , minified_name : str ) -> str | None :
1840+ """Look up the original event handler name from a minified name.
1841+
1842+ This is used when the frontend sends back minified event names
1843+ and the backend needs to find the actual event handler.
1844+
1845+ Args:
1846+ minified_name: The minified event name (e.g., 'a').
1847+
1848+ Returns:
1849+ The original event handler name, or None if not found.
1850+ """
1851+ # Build reverse lookup: minified_name -> original_name
1852+ for event_id , original_name in cls ._event_id_to_name .items ():
1853+ if _int_to_minified_name (event_id ) == minified_name :
1854+ return original_name
1855+ return None
1856+
18001857 def _get_event_handler (
18011858 self , event : Event
18021859 ) -> tuple [BaseState | StateProxy , EventHandler ]:
@@ -1819,7 +1876,17 @@ def _get_event_handler(
18191876 if not substate :
18201877 msg = "The value of state cannot be None when processing an event."
18211878 raise ValueError (msg )
1822- handler = substate .event_handlers [name ]
1879+
1880+ # Try to look up the handler directly first
1881+ handler = substate .event_handlers .get (name )
1882+ if handler is None :
1883+ # If not found, the name might be minified - try reverse lookup
1884+ original_name = substate ._get_original_event_name (name )
1885+ if original_name is not None :
1886+ handler = substate .event_handlers .get (original_name )
1887+ if handler is None :
1888+ msg = f"Event handler '{ name } ' not found in state '{ type (substate ).__name__ } '"
1889+ raise KeyError (msg )
18231890
18241891 # For background tasks, proxy the state
18251892 if handler .is_background :
0 commit comments