Browse Source

fix tag render to be recursive (#4714)

Khaleel Al-Adhami 3 months ago
parent
commit
2c3257d4ea

+ 1 - 1
reflex/.templates/jinja/web/pages/utils.js.jinja2

@@ -86,7 +86,7 @@
             {% for condition in case[:-1] %}
                 case JSON.stringify({{ condition._js_expr }}):
             {% endfor %}
-                return {{ case[-1] }};
+                return {{ render(case[-1]) }};
                 break;
         {% endfor %}
             default:

+ 2 - 2
reflex/components/component.py

@@ -2389,7 +2389,7 @@ def render_dict_to_var(tag: dict | Component | str, imported_names: set[str]) ->
     if tag["name"] == "match":
         element = tag["cond"]
 
-        conditionals = tag["default"]
+        conditionals = render_dict_to_var(tag["default"], imported_names)
 
         for case in tag["match_cases"][::-1]:
             condition = case[0].to_string() == element.to_string()
@@ -2398,7 +2398,7 @@ def render_dict_to_var(tag: dict | Component | str, imported_names: set[str]) ->
 
             conditionals = ternary_operation(
                 condition,
-                case[-1],
+                render_dict_to_var(case[-1], imported_names),
                 conditionals,
             )
 

+ 24 - 19
reflex/components/tags/tag.py

@@ -3,13 +3,33 @@
 from __future__ import annotations
 
 import dataclasses
-from typing import Any, Dict, List, Optional, Union
+from typing import Any, Dict, List, Optional, Sequence, Union
 
 from reflex.event import EventChain
 from reflex.utils import format, types
 from reflex.vars.base import LiteralVar, Var
 
 
+def render_prop(value: Any) -> Any:
+    """Render the prop.
+
+    Args:
+        value: The value to render.
+
+    Returns:
+        The rendered value.
+    """
+    from reflex.components.component import BaseComponent
+
+    if isinstance(value, BaseComponent):
+        return value.render()
+    if isinstance(value, Sequence) and not isinstance(value, str):
+        return [render_prop(v) for v in value]
+    if callable(value) and not isinstance(value, Var):
+        return None
+    return value
+
+
 @dataclasses.dataclass()
 class Tag:
     """A React tag."""
@@ -65,25 +85,10 @@ class Tag:
         Yields:
             Tuple[str, Any]: The field name and value.
         """
-        from reflex.components.component import BaseComponent
-
         for field in dataclasses.fields(self):
-            value = getattr(self, field.name)
-            if isinstance(value, list):
-                children = []
-                for child in value:
-                    if isinstance(child, BaseComponent):
-                        children.append(child.render())
-                    else:
-                        children.append(child)
-                yield field.name, children
-                continue
-            if isinstance(value, BaseComponent):
-                yield field.name, value.render()
-                continue
-            if callable(value) and not isinstance(value, Var):
-                continue
-            yield field.name, getattr(self, field.name)
+            rendered_value = render_prop(getattr(self, field.name))
+            if rendered_value is not None:
+                yield field.name, rendered_value
 
     def add_props(self, **kwargs: Optional[Any]) -> Tag:
         """Add props to the tag.

+ 6 - 6
tests/units/components/core/test_match.py

@@ -42,7 +42,7 @@ def test_match_components():
 
     assert match_cases[0][0]._js_expr == "1"
     assert match_cases[0][0]._var_type is int
-    first_return_value_render = match_cases[0][1].render()
+    first_return_value_render = match_cases[0][1]
     assert first_return_value_render["name"] == "RadixThemesText"
     assert first_return_value_render["children"][0]["contents"] == '{"first value"}'
 
@@ -50,31 +50,31 @@ def test_match_components():
     assert match_cases[1][0]._var_type is int
     assert match_cases[1][1]._js_expr == "3"
     assert match_cases[1][1]._var_type is int
-    second_return_value_render = match_cases[1][2].render()
+    second_return_value_render = match_cases[1][2]
     assert second_return_value_render["name"] == "RadixThemesText"
     assert second_return_value_render["children"][0]["contents"] == '{"second value"}'
 
     assert match_cases[2][0]._js_expr == "[1, 2]"
     assert match_cases[2][0]._var_type == List[int]
-    third_return_value_render = match_cases[2][1].render()
+    third_return_value_render = match_cases[2][1]
     assert third_return_value_render["name"] == "RadixThemesText"
     assert third_return_value_render["children"][0]["contents"] == '{"third value"}'
 
     assert match_cases[3][0]._js_expr == '"random"'
     assert match_cases[3][0]._var_type is str
-    fourth_return_value_render = match_cases[3][1].render()
+    fourth_return_value_render = match_cases[3][1]
     assert fourth_return_value_render["name"] == "RadixThemesText"
     assert fourth_return_value_render["children"][0]["contents"] == '{"fourth value"}'
 
     assert match_cases[4][0]._js_expr == '({ ["foo"] : "bar" })'
     assert match_cases[4][0]._var_type == Mapping[str, str]
-    fifth_return_value_render = match_cases[4][1].render()
+    fifth_return_value_render = match_cases[4][1]
     assert fifth_return_value_render["name"] == "RadixThemesText"
     assert fifth_return_value_render["children"][0]["contents"] == '{"fifth value"}'
 
     assert match_cases[5][0]._js_expr == f"({MatchState.get_name()}.num + 1)"
     assert match_cases[5][0]._var_type is int
-    fifth_return_value_render = match_cases[5][1].render()
+    fifth_return_value_render = match_cases[5][1]
     assert fifth_return_value_render["name"] == "RadixThemesText"
     assert fifth_return_value_render["children"][0]["contents"] == '{"sixth value"}'