nicegui consolidation
This commit is contained in:
@@ -1,119 +1,100 @@
|
||||
# Binding Dataclasses Deep Dive
|
||||
|
||||
This reference explains how to model state with NiceGUI bindable dataclasses and how to avoid common update and performance pitfalls.
|
||||
Use this reference to model NiceGUI state with bindable dataclasses and avoid common propagation and performance pitfalls.
|
||||
|
||||
## Primary Sources
|
||||
|
||||
- NiceGUI binding docs: [Binding properties](https://www.nicegui.io/documentation/section_binding_properties)
|
||||
- NiceGUI binding docs: [binding properties](https://www.nicegui.io/documentation/section_binding_properties)
|
||||
- Python dataclass docs: [dataclasses module](https://docs.python.org/3/library/dataclasses.html)
|
||||
- Data class design rationale: [PEP 557](https://peps.python.org/pep-0557/)
|
||||
|
||||
## What bindable_dataclass changes
|
||||
## Bindable Dataclass Behavior
|
||||
|
||||
`@binding.bindable_dataclass` extends standard dataclasses by turning fields into bindable properties so UI bindings can propagate immediately when a field is assigned.
|
||||
|
||||
Baseline pattern:
|
||||
`@binding.bindable_dataclass` extends standard dataclasses by turning fields into bindable properties, allowing UI bindings to propagate when a field is assigned.
|
||||
|
||||
```python
|
||||
from nicegui import binding, ui
|
||||
|
||||
|
||||
@binding.bindable_dataclass
|
||||
class Profile:
|
||||
name: str = 'Ada'
|
||||
name: str = "Ada"
|
||||
age: int = 37
|
||||
|
||||
|
||||
profile = Profile()
|
||||
|
||||
ui.input('Name').bind_value(profile, 'name')
|
||||
ui.number('Age', min=0).bind_value(profile, 'age')
|
||||
ui.label().bind_text_from(profile, 'name', backward=lambda n: f'User: {n}')
|
||||
ui.input("Name").bind_value(profile, "name")
|
||||
ui.number("Age", min=0).bind_value(profile, "age")
|
||||
ui.label().bind_text_from(profile, "name", backward=lambda name: f"User: {name}")
|
||||
```
|
||||
|
||||
## Propagation model and performance
|
||||
## Propagation And Performance
|
||||
|
||||
NiceGUI distinguishes between two link types:
|
||||
|
||||
- Bindable properties: efficient, event-like propagation on assignment.
|
||||
- Active links: polled in a refresh loop (default every 0.1s).
|
||||
- Bindable properties propagate efficiently when values are assigned.
|
||||
- Active links are checked in a refresh loop.
|
||||
|
||||
Practical implications:
|
||||
Prefer bindable dataclasses for frequently updated form state. Keep binding transforms pure and inexpensive. If an application has many active links, tune `binding_refresh_interval` in `ui.run(...)` only after measuring the impact.
|
||||
|
||||
- Prefer bindable dataclasses for frequently updated form state.
|
||||
- Keep transform functions pure and side-effect free.
|
||||
- If many active links exist, tune `binding_refresh_interval` in `ui.run(...)` carefully.
|
||||
|
||||
## Dataclass modeling rules that matter for binding
|
||||
## Dataclass Modeling Rules
|
||||
|
||||
- Use `field(default_factory=...)` for mutable defaults.
|
||||
- Avoid `frozen=True` for models that should be edited from UI controls.
|
||||
- Use `slots=True` only when you have confirmed compatibility with your inheritance and extension needs.
|
||||
- Avoid `frozen=True` for models edited by UI controls.
|
||||
- Use `slots=True` only after confirming compatibility with inheritance and extension needs.
|
||||
- Keep UI-editable fields explicit and typed.
|
||||
|
||||
Example with safe mutable defaults:
|
||||
|
||||
```python
|
||||
from dataclasses import field
|
||||
|
||||
from nicegui import binding
|
||||
|
||||
|
||||
@binding.bindable_dataclass
|
||||
class Filters:
|
||||
query: str = ''
|
||||
query: str = ""
|
||||
tags: list[str] = field(default_factory=list)
|
||||
```
|
||||
|
||||
## Nested structures and binding paths
|
||||
## Nested Structures
|
||||
|
||||
NiceGUI supports nested key paths via tuples for nested data (for example dictionaries and nested structures).
|
||||
NiceGUI supports tuple paths for nested data structures.
|
||||
|
||||
```python
|
||||
from nicegui import ui
|
||||
|
||||
data = {'user': {'name': 'Ada'}}
|
||||
data = {"user": {"name": "Ada"}}
|
||||
|
||||
ui.input('Name').bind_value(data, ('user', 'name'))
|
||||
ui.label().bind_text_from(data, ('user', 'name'))
|
||||
ui.input("Name").bind_value(data, ("user", "name"))
|
||||
ui.label().bind_text_from(data, ("user", "name"))
|
||||
```
|
||||
|
||||
When using nested dataclasses, keep updates explicit and predictable at the field level.
|
||||
Keep nested dataclass updates explicit and predictable at the field level.
|
||||
|
||||
## Strictness and refactor safety
|
||||
|
||||
Binding can warn when attributes do not exist.
|
||||
## Strictness And Refactor Safety
|
||||
|
||||
- Object attributes are checked by default.
|
||||
- Dictionary keys are not checked by default.
|
||||
- Use `strict=True` when you want missing-key warnings for dict-backed state.
|
||||
- Use `strict=True` when missing dictionary keys should produce warnings.
|
||||
|
||||
```python
|
||||
from nicegui import app, ui
|
||||
|
||||
ui.input().bind_value(app.storage.user, 'display_name', strict=True)
|
||||
ui.input().bind_value(app.storage.user, "display_name", strict=True)
|
||||
```
|
||||
|
||||
## Common pitfalls and safer alternatives
|
||||
## Common Pitfalls
|
||||
|
||||
- Pitfall: mutating nested mutable values in place and expecting immediate UI sync.
|
||||
- Safer alternative: assign back to the bound field after updates so change propagation is explicit.
|
||||
- In-place mutation may not produce immediate UI synchronization. Assign the updated value back to the bound field.
|
||||
- Heavy binding transforms can degrade refresh performance. Move expensive work to event handlers or services.
|
||||
- State shared across unrelated pages or users can leak data. Scope models to the appropriate page, client, or user context.
|
||||
|
||||
- Pitfall: heavy transform functions in bindings.
|
||||
- Safer alternative: keep transformations cheap and deterministic; move heavy work to event handlers.
|
||||
## Version Checks
|
||||
|
||||
- Pitfall: one model shared across unrelated pages or users.
|
||||
- Safer alternative: scope model instances to page/client/user context as needed.
|
||||
- `bindable_dataclass` was added in NiceGUI 2.11.0.
|
||||
- Depth-first binding propagation was documented in NiceGUI 2.16.0.
|
||||
- Binding `strict` behavior was documented in NiceGUI 3.0.0.
|
||||
- Tuple paths for nested properties were documented in NiceGUI 3.10.0.
|
||||
|
||||
## Version notes to remember
|
||||
|
||||
- `bindable_dataclass` added in NiceGUI 2.11.0.
|
||||
- Binding `strict` behavior documented as added in NiceGUI 3.0.0.
|
||||
- Tuple paths for nested properties documented as added in NiceGUI 3.10.0.
|
||||
- Depth-first binding propagation update documented in NiceGUI 2.16.0.
|
||||
|
||||
Verify behavior against the NiceGUI version pinned in your project before relying on version-specific semantics.
|
||||
|
||||
## Quick checklist
|
||||
|
||||
- Choose bindable dataclasses for interactive form-like state.
|
||||
- Use `default_factory` for mutable fields.
|
||||
- Keep transform functions pure.
|
||||
- Use strict mode intentionally.
|
||||
- Re-check version notes before migration work.
|
||||
Verify these behaviors against the NiceGUI version pinned by the target project.
|
||||
Reference in New Issue
Block a user