2727logger = logging .getLogger (__name__ )
2828
2929
30+ # TODO: Make maxsize configurable
3031# Module cache to store the found component classes
3132views_cache = LRUCache (maxsize = 100 )
3233
34+ # Module cache for constructed component classes
35+ # This can create a subtle race condition so a more long-term solution needs to be found
36+ constructed_views_cache = LRUCache (maxsize = 100 )
37+
3338
3439class UnicornField :
3540 """
@@ -166,6 +171,38 @@ def get_locations(component_name):
166171 return locations
167172
168173
174+ @timed
175+ def construct_component (
176+ component_class ,
177+ component_id ,
178+ component_name ,
179+ component_key ,
180+ parent ,
181+ request ,
182+ ** kwargs ,
183+ ):
184+ """
185+ Constructs a class instance.
186+ """
187+ component = component_class (
188+ component_id = component_id ,
189+ component_name = component_name ,
190+ component_key = component_key ,
191+ parent = parent ,
192+ request = request ,
193+ ** kwargs ,
194+ )
195+
196+ component .children = []
197+ component ._children_set = False
198+
199+ component .mount ()
200+ component .hydrate ()
201+ component ._validate_called = False
202+
203+ return component
204+
205+
169206class UnicornTemplateResponse (TemplateResponse ):
170207 def __init__ (
171208 self ,
@@ -726,6 +763,7 @@ def create(
726763 component_key : str = "" ,
727764 parent : "UnicornView" = None ,
728765 request : HttpRequest = None ,
766+ use_cache = True ,
729767 kwargs : Dict [str , Any ] = {},
730768 ) -> "UnicornView" :
731769 """
@@ -759,40 +797,18 @@ def _get_component_class(
759797
760798 return component_class
761799
762- @timed
763- def _construct_component (
764- component_class ,
765- component_id ,
766- component_name ,
767- component_key ,
768- parent ,
769- request ,
770- ** kwargs ,
771- ):
772- """
773- Constructs a class instance.
774- """
775- component = component_class (
776- component_id = component_id ,
777- component_name = component_name ,
778- component_key = component_key ,
779- parent = parent ,
780- request = request ,
781- ** kwargs ,
782- )
783-
784- component .children = []
785- component ._children_set = False
786-
787- component .mount ()
788- component .hydrate ()
800+ if use_cache and component_id in constructed_views_cache :
801+ component = constructed_views_cache [component_id ]
802+ component .setup (request )
789803 component ._validate_called = False
804+ logger .debug (f"Retrieve { component_id } from constructed views cache" )
790805
791806 return component
792807
793808 if component_id in views_cache :
794- component_class = views_cache [component_id ]
795- component = _construct_component (
809+ (component_class , parent , kwargs ) = views_cache [component_id ]
810+
811+ component = construct_component (
796812 component_class = component_class ,
797813 component_id = component_id ,
798814 component_name = component_name ,
@@ -815,7 +831,7 @@ def _construct_component(
815831 for (class_name , module_name ) in locations :
816832 try :
817833 component_class = _get_component_class (module_name , class_name )
818- component = _construct_component (
834+ component = construct_component (
819835 component_class = component_class ,
820836 component_id = component_id ,
821837 component_name = component_name ,
@@ -824,8 +840,10 @@ def _construct_component(
824840 request = request ,
825841 ** kwargs ,
826842 )
843+
827844 # Put the component's class in a "cache" to skip looking for the component on the next request
828- views_cache [component_id ] = component_class
845+ views_cache [component_id ] = (component_class , parent , kwargs )
846+ constructed_views_cache [component_id ] = component
829847
830848 return component
831849 except ModuleNotFoundError as e :
0 commit comments