Skip to content
This repository was archived by the owner on Apr 28, 2026. It is now read-only.

Commit ab8b239

Browse files
Address PR feedback: improve serialization documentation
Co-Authored-By: Alek Petuskey <alek@pynecone.io>
1 parent 505b949 commit ab8b239

1 file changed

Lines changed: 59 additions & 92 deletions

File tree

docs/vars/serialization.md

Lines changed: 59 additions & 92 deletions
Original file line numberDiff line numberDiff line change
@@ -65,12 +65,47 @@ class SerializationDemoState(rx.State):
6565
def serialization_demo():
6666
return rx.vstack(
6767
rx.heading("State Variables", size="4"),
68-
rx.text(f"number: {SerializationDemoState.number}"),
69-
rx.text(f"text: {SerializationDemoState.text}"),
70-
rx.text(f"is_active: {SerializationDemoState.is_active}"),
71-
rx.text(f"items: {SerializationDemoState.items}"),
72-
rx.text(f"settings: {SerializationDemoState.settings}"),
73-
rx.text(f"coordinates: {SerializationDemoState.coordinates}"),
68+
rx.table(
69+
rx.thead(
70+
rx.tr(
71+
rx.th("Variable"),
72+
rx.th("Type"),
73+
rx.th("Value"),
74+
)
75+
),
76+
rx.tbody(
77+
rx.tr(
78+
rx.td("number"),
79+
rx.td("int"),
80+
rx.td(f"{SerializationDemoState.number}"),
81+
),
82+
rx.tr(
83+
rx.td("text"),
84+
rx.td("str"),
85+
rx.td(f"{SerializationDemoState.text}"),
86+
),
87+
rx.tr(
88+
rx.td("is_active"),
89+
rx.td("bool"),
90+
rx.td(f"{SerializationDemoState.is_active}"),
91+
),
92+
rx.tr(
93+
rx.td("items"),
94+
rx.td("list[str]"),
95+
rx.td(f"{SerializationDemoState.items}"),
96+
),
97+
rx.tr(
98+
rx.td("settings"),
99+
rx.td("dict[str, Any]"),
100+
rx.td(f"{SerializationDemoState.settings}"),
101+
),
102+
rx.tr(
103+
rx.td("coordinates"),
104+
rx.td("tuple[int, int]"),
105+
rx.td(f"{SerializationDemoState.coordinates}"),
106+
),
107+
),
108+
),
74109
rx.divider(),
75110
rx.heading("JSON Serialized State", size="4"),
76111
rx.code_block(SerializationDemoState.serialized_state, language="json"),
@@ -108,7 +143,7 @@ def backend_only_demo():
108143
rx.button("Calculate Summary", on_click=BackendOnlyState.calculate_summary),
109144
rx.divider(),
110145
rx.heading("Data Summary", size="4"),
111-
rx.code_block(str(BackendOnlyState.data_summary), language="json"),
146+
rx.code_block(BackendOnlyState.data_summary, language="json"),
112147
width="100%",
113148
)
114149
```
@@ -231,61 +266,9 @@ def serializer_demo():
231266
)
232267
```
233268

234-
## The `.to` Operator and Type Checking
235-
236-
One of the most common sources of errors in Reflex applications is related to type checking and the `.to` operator. Reflex needs to know the types of variables at compile time to generate the correct JavaScript code.
237-
238-
### Understanding the `.to` Operator
239-
240-
The `.to` operator allows you to convert a Var from one type to another. This is particularly useful when you need to ensure a specific type for an operation:
241-
242-
```python
243-
# Example of using the .to operator in a component
244-
# Note: This is a code example, not a runnable demo
245-
class TypeConversionState(rx.State):
246-
text_value: str = "42"
247-
248-
@rx.var
249-
def as_number(self) -> int:
250-
# In actual Reflex code, state vars have a .to method
251-
# that converts them to a different type
252-
# This is just an example - in real code you would use:
253-
# return self.text_value.to(int)
254-
return int(self.text_value)
255-
256-
@rx.event
257-
def increment(self):
258-
# Convert to int, increment, then convert back to string
259-
self.text_value = str(int(self.text_value) + 1)
269+
## Type Checking and Type Conversion
260270

261-
# In a component, you would use .to like this:
262-
# rx.text(State.some_number.to(str))
263-
# rx.progress(value=State.some_string.to(int))
264-
```
265-
266-
```python demo exec
267-
# Simple demo without using .to operator
268-
class SimpleConversionState(rx.State):
269-
text_value: str = "42"
270-
271-
@rx.var
272-
def as_number(self) -> int:
273-
# Simple conversion without .to
274-
return int(self.text_value)
275-
276-
@rx.event
277-
def increment(self):
278-
self.text_value = str(int(self.text_value) + 1)
279-
280-
def type_conversion_demo():
281-
return rx.vstack(
282-
rx.heading("Type Conversion Example", size="4"),
283-
rx.text(f"Text value: {SimpleConversionState.text_value} (type: str)"),
284-
rx.text(f"As number: {SimpleConversionState.as_number} (type: int)"),
285-
rx.button("Increment", on_click=SimpleConversionState.increment),
286-
width="100%",
287-
)
288-
```
271+
One of the most common sources of errors in Reflex applications is related to type checking. Reflex needs to know the types of variables at compile time to generate the correct JavaScript code.
289272

290273
### Common Type Errors and Solutions
291274

@@ -299,7 +282,7 @@ Error: Invalid var passed for prop value, expected type <class 'int'>, got value
299282

300283
This error occurs when Reflex cannot determine the type of a variable at compile time. To fix it:
301284

302-
1. **Add explicit type annotations to your state variables:**
285+
1. **Always use explicit type annotations for your state variables:**
303286

304287
```python
305288
# Incorrect - type is Any
@@ -309,14 +292,7 @@ items: list = [1, 2, 3]
309292
items: list[int] = [1, 2, 3]
310293
```
311294

312-
2. **Use the `.to` operator to convert to the expected type:**
313-
314-
```python
315-
# If you need to pass a list item to a component expecting an int
316-
rx.progress(value=State.items[0].to(int))
317-
```
318-
319-
3. **For nested structures, be specific about all types:**
295+
2. **For nested structures, be specific about all types:**
320296

321297
```python
322298
# Incorrect
@@ -329,6 +305,13 @@ users: list[dict[str, Any]] = [dict(name="Alice", scores=[10, 20])]
329305
users: list[dict[str, Union[str, list[int]]]] = [dict(name="Alice", scores=[10, 20])]
330306
```
331307

308+
3. **As a fallback, use the `.to` operator to convert to the expected type:**
309+
310+
```python
311+
# If you need to pass a list item to a component expecting an int
312+
rx.progress(value=State.items[0].to(int))
313+
```
314+
332315
## Serialization with Browser Storage
333316

334317
When using `rx.LocalStorage` or `rx.Cookie` for client-side persistence, you need to consider serialization strategies:
@@ -407,26 +390,7 @@ Some Python types cannot be automatically serialized:
407390
- **Database connections**: Store connection parameters, not the connection itself
408391
- **Complex objects**: Use custom serializers or convert to basic types
409392

410-
### 2. Circular References
411-
412-
Objects that reference each other in a circular manner can cause serialization errors:
413-
414-
```python
415-
# Problematic circular reference
416-
class A:
417-
def __init__(self):
418-
self.b = None
419-
420-
class B:
421-
def __init__(self, a):
422-
self.a = a
423-
424-
a = A()
425-
b = B(a)
426-
a.b = b # Creates a circular reference
427-
```
428393

429-
Solution: Break the circular reference or use a custom serializer that handles this case.
430394

431395
### 3. Large Data Structures
432396

@@ -441,9 +405,9 @@ Sending large data structures between frontend and backend can cause performance
441405
4. Use cached vars to minimize recalculation
442406
```
443407

444-
### 4. Type Inconsistency
408+
### 2. Type Inconsistency
445409

446-
Ensure consistent types between frontend and backend:
410+
Always use strict typing and ensure consistent types between frontend and backend:
447411

448412
```python
449413
# Problematic - type changes during serialization
@@ -455,7 +419,10 @@ class State(rx.State):
455419
self.value = "42" # Now it's a string!
456420
```
457421

458-
Solution: Use explicit type annotations and consistent types, or use the `.to` operator to ensure type consistency.
422+
Solution:
423+
1. Use explicit type annotations for all state variables
424+
2. Maintain consistent types throughout your application
425+
3. As a fallback, use the `.to` operator when you need to convert between types
459426

460427
## Conclusion
461428

0 commit comments

Comments
 (0)