@@ -306,11 +306,13 @@ def __init__(
306306 """
307307 if "children" in kwargs :
308308 kwargs ["children" ] = tuple (kwargs ["children" ])
309- for key , value in kwargs .items ():
310- setattr (self , key , value )
309+ # Bypass ``__setattr__``'s freeze guard: a brand-new instance can't be
310+ # frozen, so the per-attribute check is pure overhead during init.
311+ d = vars (self )
312+ d .update (kwargs )
311313 for name , value in self .get_fields ().items ():
312314 if name not in kwargs :
313- setattr ( self , name , value .default_value () )
315+ d [ name ] = value .default_value ()
314316
315317 def __setattr__ (self , key : str , value : Any ) -> None :
316318 """Block writes to frozen components, except for cache attributes.
@@ -946,76 +948,70 @@ def _post_init(self, *args, **kwargs):
946948 component_specific_triggers = self .get_event_triggers ()
947949 props = self .get_props ()
948950
949- # Add any events triggers.
950- if "event_triggers" not in kwargs :
951- kwargs ["event_triggers" ] = {}
952- kwargs ["event_triggers" ] = kwargs ["event_triggers" ].copy ()
951+ # Lazily allocate the event_triggers dict only when a trigger is found.
952+ # Most components have no events; allocating up-front is pure waste.
953+ existing_triggers = kwargs .get ("event_triggers" )
954+ event_triggers : dict [str , Any ] | None = (
955+ dict (existing_triggers ) if existing_triggers else None
956+ )
957+ event_keys : list [str ] = []
953958
954959 # Iterate through the kwargs and set the props.
955960 for key , value in kwargs .items ():
956- if (
957- key .startswith ("on_" )
958- and key not in component_specific_triggers
959- and key not in props
960- ):
961- valid_triggers = sorted (component_specific_triggers .keys ())
962- msg = (
963- f"The { (comp_name := type (self ).__name__ )} does not take in an `{ key } ` event trigger. "
964- f"Valid triggers for { comp_name } : { valid_triggers } . "
965- f"If { comp_name } is a third party component make sure to add `{ key } ` to the component's event triggers. "
966- f"visit https://reflex.dev/docs/wrapping-react/guide/#event-triggers for more info."
967- )
968- raise ValueError (msg )
969961 if key in component_specific_triggers :
970- # Event triggers are bound to event chains.
971- is_var = False
972- elif key in props :
973- # Set the field type.
974- is_var = (
975- field . type_origin is Var if ( field := fields . get ( key )) else False
962+ if event_triggers is None :
963+ event_triggers = {}
964+ event_triggers [ key ] = EventChain . create (
965+ value = value ,
966+ args_spec = component_specific_triggers [ key ],
967+ key = key ,
976968 )
977- else :
969+ event_keys . append ( key )
978970 continue
979971
980- # Check whether the key is a component prop.
981- if is_var :
972+ if key in props :
973+ field = fields .get (key )
974+ if field is None or field .type_origin is not Var :
975+ continue
982976 try :
983977 kwargs [key ] = LiteralVar .create (value )
984-
985- # Get the passed type and the var type.
986978 passed_type = kwargs [key ]._var_type
987979 expected_type = typing .get_args (
988980 types .get_field_type (type (self ), key )
989981 )[0 ]
990982 except TypeError :
991- # If it is not a valid var, check the base types.
992983 passed_type = type (value )
993984 expected_type = types .get_field_type (type (self ), key )
994985
995986 if not satisfies_type_hint (value , expected_type ):
996987 value_name = value ._js_expr if isinstance (value , Var ) else value
997-
998988 additional_info = (
999989 " You can call `.bool()` on the value to convert it to a boolean."
1000990 if expected_type is bool and isinstance (value , Var )
1001991 else ""
1002992 )
1003-
1004993 raise TypeError (
1005994 f"Invalid var passed for prop { type (self ).__name__ } .{ key } , expected type { expected_type } , got value { value_name } of type { passed_type } ."
1006995 + additional_info
1007996 )
1008- # Check if the key is an event trigger.
1009- if key in component_specific_triggers :
1010- kwargs ["event_triggers" ][key ] = EventChain .create (
1011- value = value ,
1012- args_spec = component_specific_triggers [key ],
1013- key = key ,
997+ continue
998+
999+ if key .startswith ("on_" ):
1000+ valid_triggers = sorted (component_specific_triggers .keys ())
1001+ comp_name = type (self ).__name__
1002+ msg = (
1003+ f"The { comp_name } does not take in an `{ key } ` event trigger. "
1004+ f"Valid triggers for { comp_name } : { valid_triggers } . "
1005+ f"If { comp_name } is a third party component make sure to add `{ key } ` to the component's event triggers. "
1006+ f"visit https://reflex.dev/docs/wrapping-react/guide/#event-triggers for more info."
10141007 )
1008+ raise ValueError (msg )
10151009
1016- # Remove any keys that were added as events.
1017- for key in kwargs ["event_triggers" ]:
1018- kwargs .pop (key , None )
1010+ # Promote any registered event triggers; drop the raw on_* keys.
1011+ if event_triggers is not None :
1012+ kwargs ["event_triggers" ] = event_triggers
1013+ for key in event_keys :
1014+ kwargs .pop (key , None )
10191015
10201016 # Place data_ and aria_ attributes into custom_attrs
10211017 special_attributes = [
@@ -1086,9 +1082,9 @@ def _post_init(self, *args, **kwargs):
10861082 ):
10871083 msg = f"Invalid class_name passed for prop { type (self ).__name__ } .class_name, expected type str, got value { class_name ._js_expr } of type { class_name ._var_type } ."
10881084 raise TypeError (msg )
1089- # Construct the component.
1090- for key , value in kwargs . items ():
1091- setattr (self , key , value )
1085+ # Construct the component. Bypass ``__setattr__``'s freeze guard: the
1086+ # instance is freshly created and not yet frozen.
1087+ vars (self ). update ( kwargs )
10921088
10931089 @classmethod
10941090 def get_event_triggers (cls ) -> dict [str , types .ArgsSpec | Sequence [types .ArgsSpec ]]:
@@ -1300,8 +1296,8 @@ def _unsafe_create(
13001296 children_tuple = tuple (children )
13011297 comp = cls .__new__ (cls )
13021298 super (Component , comp ).__init__ (id = props .get ("id" ), children = children_tuple )
1303- for prop , value in props . items ():
1304- setattr (comp , prop , value )
1299+ # Bypass ``__setattr__``'s freeze guard: ``comp`` is not yet frozen.
1300+ vars (comp ). update ( props )
13051301 comp ._freeze ()
13061302 return comp
13071303
@@ -1533,19 +1529,18 @@ def _validate_component_children(self, children: list[Component]):
15331529 children: The children of the component.
15341530
15351531 """
1536- from reflex_components_core .base .fragment import Fragment
1537- from reflex_components_core .core .cond import Cond
1538- from reflex_components_core .core .foreach import Foreach
1539- from reflex_components_core .core .match import Match
1540-
1541- no_valid_parents_defined = all (child ._valid_parents == [] for child in children )
15421532 if (
15431533 not self ._invalid_children
15441534 and not self ._valid_children
1545- and no_valid_parents_defined
1535+ and all ( child . _valid_parents == [] for child in children )
15461536 ):
15471537 return
15481538
1539+ from reflex_components_core .base .fragment import Fragment
1540+ from reflex_components_core .core .cond import Cond
1541+ from reflex_components_core .core .foreach import Foreach
1542+ from reflex_components_core .core .match import Match
1543+
15491544 comp_name = type (self ).__name__
15501545 allowed_components = [
15511546 comp .__name__ for comp in (Fragment , Foreach , Cond , Match )
0 commit comments