Skip to content

Commit 3f3fddb

Browse files
refactor Component rendering by introducing BoundComponent class (#134)
1 parent fb1491d commit 3f3fddb

File tree

4 files changed

+48
-17
lines changed

4 files changed

+48
-17
lines changed

CHANGELOG.md

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -18,6 +18,14 @@ and this project attempts to adhere to [Semantic Versioning](https://semver.org/
1818

1919
## [Unreleased]
2020

21+
### Changed
22+
23+
- **Internal**: Refactored component rendering by introducing a new `BoundComponent` class and moving some of the rendering logic from `Component` and `BirdNode` to this new class.
24+
25+
### Removed
26+
27+
- **Internal**: Removed `Component.render` method in favor of new `BoundComponent.render` method.
28+
2129
## [0.11.2]
2230

2331
### Changed

src/django_bird/components.py

Lines changed: 29 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -14,6 +14,9 @@
1414
from django.template.exceptions import TemplateDoesNotExist
1515
from django.template.loader import select_template
1616

17+
from django_bird.params import Param
18+
from django_bird.params import Params
19+
from django_bird.params import Value
1720
from django_bird.staticfiles import Asset
1821

1922
from .conf import app_settings
@@ -33,8 +36,9 @@ def get_asset(self, asset_filename: str) -> Asset | None:
3336
return asset
3437
return None
3538

36-
def render(self, context: Context):
37-
return self.template.template.render(context)
39+
def get_bound_component(self, attrs: list[Param]):
40+
params = Params.with_attrs(attrs)
41+
return BoundComponent(component=self, params=params)
3842

3943
@property
4044
def id(self):
@@ -72,6 +76,29 @@ def from_name(cls, name: str):
7276
return cls(name=name, template=template, assets=frozenset(assets))
7377

7478

79+
@dataclass
80+
class BoundComponent:
81+
component: Component
82+
params: Params
83+
84+
def render(self, context: Context):
85+
if app_settings.ENABLE_BIRD_ID_ATTR:
86+
self.params.attrs.append(
87+
Param("data_bird_id", Value(self.component.id, True))
88+
)
89+
90+
props = self.params.render_props(self.component.nodelist, context)
91+
attrs = self.params.render_attrs(context)
92+
93+
with context.push(
94+
**{
95+
"attrs": attrs,
96+
"props": props,
97+
}
98+
):
99+
return self.component.template.template.render(context)
100+
101+
75102
class ComponentRegistry:
76103
def __init__(self, maxsize: int = 100):
77104
self._components: LRUCache[str, Component] = LRUCache(maxsize=maxsize)

src/django_bird/templatetags/tags/bird.py

Lines changed: 3 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -13,10 +13,7 @@
1313
from django_bird._typing import override
1414
from django_bird.components import Component
1515
from django_bird.components import components
16-
from django_bird.conf import app_settings
1716
from django_bird.params import Param
18-
from django_bird.params import Params
19-
from django_bird.params import Value
2017
from django_bird.slots import DEFAULT_SLOT
2118
from django_bird.slots import Slots
2219

@@ -77,11 +74,12 @@ def render(self, context: Context) -> str:
7774
component_name = self.get_component_name(context)
7875
component = components.get_component(component_name)
7976
component_context = self.get_component_context_data(component, context)
77+
bound_component = component.get_bound_component(attrs=self.attrs)
8078

8179
if self.isolated_context:
82-
return component.render(context.new(component_context))
80+
return bound_component.render(context.new(component_context))
8381
with context.push(**component_context):
84-
return component.render(context)
82+
return bound_component.render(context)
8583

8684
def get_component_name(self, context: Context) -> str:
8785
try:
@@ -93,18 +91,10 @@ def get_component_name(self, context: Context) -> str:
9391
def get_component_context_data(
9492
self, component: Component, context: Context
9593
) -> dict[str, Any]:
96-
if app_settings.ENABLE_BIRD_ID_ATTR:
97-
self.attrs.append(Param("data_bird_id", Value(component.id, True)))
98-
99-
params = Params.with_attrs(self.attrs)
100-
props = params.render_props(component.nodelist, context)
101-
attrs = params.render_attrs(context)
10294
slots = Slots.collect(self.nodelist, context).render()
10395
default_slot = slots.get(DEFAULT_SLOT) or context.get("slot")
10496

10597
return {
106-
"attrs": attrs,
107-
"props": props,
10898
"slot": default_slot,
10999
"slots": slots,
110100
}

tests/test_components.py

Lines changed: 8 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -34,7 +34,10 @@ def test_from_name_basic(self, templates_dir):
3434

3535
assert comp.name == "button"
3636
assert isinstance(comp.template, Template)
37-
assert comp.render(Context({})) == "<button>Click me</button>"
37+
38+
bound = comp.get_bound_component([])
39+
40+
assert bound.render(Context({})) == "<button>Click me</button>"
3841

3942
def test_from_name_with_assets(self, templates_dir):
4043
button = TestComponent(
@@ -104,7 +107,10 @@ def test_from_name_custom_component_dir(self, templates_dir, override_app_settin
104107

105108
assert comp.name == "button"
106109
assert isinstance(comp.template, Template)
107-
assert comp.render(Context({})) == "<button>Click me</button>"
110+
111+
bound = comp.get_bound_component([])
112+
113+
assert bound.render(Context({})) == "<button>Click me</button>"
108114

109115
def test_id_is_consistent(self, templates_dir):
110116
button = TestComponent(

0 commit comments

Comments
 (0)