Skip to content

Commit c1af36b

Browse files
authored
Add json-tree example app (#281)
* Add json-tree example app This app shows off a common use case of dynamic components. * requirements.txt: use a lower bound instead of strict version
1 parent 95ac506 commit c1af36b

File tree

6 files changed

+86
-0
lines changed

6 files changed

+86
-0
lines changed

json-tree/README.md

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,13 @@
1+
# json-tree
2+
3+
This example demonstrates "dynamic components", wherein a component is created
4+
and stored in a State var or returned from a computed var. Dynamic components can be
5+
constructed imperatively from complex data without having to
6+
use `rx.cond` or `rx.foreach` as is required for normal UI components.
7+
8+
Although dynamic components can be less performant and affect SEO, they are more
9+
flexible when rendering nested data and allow components to be constructed using
10+
regular python code.
11+
12+
To use the example app, paste in valid JSON and see the structure of the JSON
13+
displayed as a nested `rx.data_list`.

json-tree/assets/favicon.ico

4.19 KB
Binary file not shown.

json-tree/json_tree/__init__.py

Whitespace-only changes.

json-tree/json_tree/json_tree.py

Lines changed: 67 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,67 @@
1+
"""Render nested JSON data as a tree using `rx.data_list`"""
2+
3+
import json
4+
5+
import reflex as rx
6+
7+
8+
class State(rx.State):
9+
_json: str = ""
10+
info: rx.Component = rx.text("Paste JSON data")
11+
12+
@rx.var(cache=True)
13+
def comp_json_view(self) -> rx.Component:
14+
if not self._json:
15+
return rx.text("No JSON data")
16+
try:
17+
obj = json.loads(self._json)
18+
except json.JSONDecodeError as e:
19+
return rx.text(f"Invalid JSON: {e}")
20+
21+
def make_json(node) -> rx.Component:
22+
children = []
23+
if isinstance(node, dict):
24+
for key, value in node.items():
25+
children.append(
26+
rx.data_list.item(
27+
rx.data_list.label(key),
28+
rx.data_list.value(make_json(value)),
29+
),
30+
)
31+
return rx.data_list.root(*children, margin_bottom="1rem")
32+
if isinstance(node, list):
33+
for item in node:
34+
children.append(rx.list_item(make_json(item)))
35+
return rx.unordered_list(*children)
36+
return rx.text(str(node))
37+
38+
return make_json(obj)
39+
40+
@rx.event
41+
def handle_paste_json(self, data: list[tuple[str, str]]):
42+
self.info = rx.spinner()
43+
yield
44+
for mime_type, raw in data:
45+
if mime_type == "text/plain":
46+
try:
47+
json.loads(raw)
48+
self._json = raw
49+
self.info = rx.text(f"Loaded {len(raw)} bytes of JSON data.")
50+
except json.JSONDecodeError:
51+
self._json = ""
52+
break
53+
54+
55+
def index() -> rx.Component:
56+
return rx.fragment(
57+
rx.vstack(
58+
State.info,
59+
State.comp_json_view,
60+
padding_x="10px",
61+
),
62+
rx.clipboard(on_paste=State.handle_paste_json),
63+
)
64+
65+
66+
app = rx.App()
67+
app.add_page(index)

json-tree/requirements.txt

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
reflex>=0.6.5

json-tree/rxconfig.py

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
import reflex as rx
2+
3+
config = rx.Config(
4+
app_name="json_tree",
5+
)

0 commit comments

Comments
 (0)