22import inspect
33from functools import wraps
44from typing import TYPE_CHECKING , Dict , Callable , Any , Tuple , Union
5+ from weakref import ReferenceType
56
7+ from .hooks import LifeCycleHook
68
79if TYPE_CHECKING : # pragma: no cover
810 from .vdom import VdomDict # noqa
@@ -28,16 +30,41 @@ def constructor(*args: Any, **kwargs: Any) -> Component:
2830
2931
3032class AbstractComponent (abc .ABC ):
33+ """A base class for all component implementations"""
3134
32- __slots__ = [] if hasattr (abc .ABC , "__weakref__" ) else ["__weakref__" ]
35+ __slots__ = ["_life_cycle_hook" ]
36+ if not hasattr (abc .ABC , "__weakref__" ):
37+ __slots__ .append ("__weakref__" )
38+
39+ # When a LifeCyleHook is created it will bind a WeakReference of itself to the its
40+ # component. This is only useful for class-based component implementations. For
41+ # functional components, the LifeCycleHook is accessed by getting the current_hook().
42+ _life_cycle_hook : "ReferenceType[LifeCycleHook]"
3343
3444 @abc .abstractmethod
3545 def render (self ) -> "VdomDict" :
3646 """Render the component's :ref:`VDOM <VDOM Mimetype>` model."""
3747
48+ def schedule_render (self ):
49+ """Schedule a re-render of this component
50+
51+ This is only used by class-based component implementations. Most components
52+ should be functional components that use hooks to schedule renders and save
53+ state.
54+ """
55+ try :
56+ hook = self ._life_cycle_hook ()
57+ except AttributeError :
58+ raise RuntimeError (
59+ f"Component { self } has no hook. Are you rendering in a layout?"
60+ )
61+ else :
62+ assert hook is not None , f"LifeCycleHook for { self } no longer exists"
63+ hook .schedule_render ()
64+
3865
3966class Component (AbstractComponent ):
40- """An object for rending component models. """
67+ """A functional component"""
4168
4269 __slots__ = (
4370 "_function" ,
0 commit comments