mirror of
https://github.com/Textualize/textual.git
synced 2025-10-17 02:38:12 +03:00
added reactive to reference docs
This commit is contained in:
1
docs/reference/reactive.md
Normal file
1
docs/reference/reactive.md
Normal file
@@ -0,0 +1 @@
|
|||||||
|
::: textual.reactive.Reactive
|
||||||
@@ -338,7 +338,7 @@ If you run "stopwatch04.py" now you will be able to toggle between the two state
|
|||||||
|
|
||||||
A recurring theme in Textual is that you rarely need to explicitly update a widget. It is possible: you can call [`refresh()`][textual.widget.Widget.refresh] to display new data. However, Textual prefers to do this automatically via _reactive_ attributes.
|
A recurring theme in Textual is that you rarely need to explicitly update a widget. It is possible: you can call [`refresh()`][textual.widget.Widget.refresh] to display new data. However, Textual prefers to do this automatically via _reactive_ attributes.
|
||||||
|
|
||||||
You can declare a reactive attribute with `textual.reactive.Reactive`. Let's use this feature to create a timer that displays elapsed time and keeps it updated.
|
You can declare a reactive attribute with [Reactive][textual.reactive.Reactive]. Let's use this feature to create a timer that displays elapsed time and keeps it updated.
|
||||||
|
|
||||||
```python title="stopwatch04.py" hl_lines="1 5 12-27"
|
```python title="stopwatch04.py" hl_lines="1 5 12-27"
|
||||||
--8<-- "docs/examples/tutorial/stopwatch05.py"
|
--8<-- "docs/examples/tutorial/stopwatch05.py"
|
||||||
|
|||||||
@@ -1,19 +1,10 @@
|
|||||||
from __future__ import annotations
|
from __future__ import annotations
|
||||||
|
|
||||||
from inspect import isawaitable
|
|
||||||
from functools import partial
|
from functools import partial
|
||||||
from typing import (
|
from inspect import isawaitable
|
||||||
Any,
|
from typing import TYPE_CHECKING, Any, Callable, Generic, Type, TypeVar, Union
|
||||||
Callable,
|
|
||||||
Generic,
|
|
||||||
Type,
|
|
||||||
Union,
|
|
||||||
TypeVar,
|
|
||||||
TYPE_CHECKING,
|
|
||||||
)
|
|
||||||
|
|
||||||
from . import events
|
from . import events
|
||||||
|
|
||||||
from ._callback import count_parameters, invoke
|
from ._callback import count_parameters, invoke
|
||||||
from ._types import MessageTarget
|
from ._types import MessageTarget
|
||||||
|
|
||||||
@@ -31,7 +22,15 @@ T = TypeVar("T")
|
|||||||
|
|
||||||
|
|
||||||
class Reactive(Generic[ReactiveType]):
|
class Reactive(Generic[ReactiveType]):
|
||||||
"""Reactive descriptor."""
|
"""Reactive descriptor.
|
||||||
|
|
||||||
|
Args:
|
||||||
|
default (ReactiveType | Callable[[], ReactiveType]): A default value or callable that returns a default.
|
||||||
|
layout (bool, optional): Perform a layout on change. Defaults to False.
|
||||||
|
repaint (bool, optional): Perform a repaint on change. Defaults to True.
|
||||||
|
init (bool, optional): Call watchers on initialize (post mount). Defaults to False.
|
||||||
|
|
||||||
|
"""
|
||||||
|
|
||||||
def __init__(
|
def __init__(
|
||||||
self,
|
self,
|
||||||
@@ -41,14 +40,6 @@ class Reactive(Generic[ReactiveType]):
|
|||||||
repaint: bool = True,
|
repaint: bool = True,
|
||||||
init: bool = False,
|
init: bool = False,
|
||||||
) -> None:
|
) -> None:
|
||||||
"""Create a Reactive Widget attribute,
|
|
||||||
|
|
||||||
Args:
|
|
||||||
default (ReactiveType | Callable[[], ReactiveType]): A default value or callable that returns a default.
|
|
||||||
layout (bool, optional): Perform a layout on change. Defaults to False.
|
|
||||||
repaint (bool, optional): Perform a repaint on change. Defaults to True.
|
|
||||||
init (bool, optional): Call watchers on initialize (post mount). Defaults to False.
|
|
||||||
"""
|
|
||||||
self._default = default
|
self._default = default
|
||||||
self._layout = layout
|
self._layout = layout
|
||||||
self._repaint = repaint
|
self._repaint = repaint
|
||||||
@@ -138,12 +129,12 @@ class Reactive(Generic[ReactiveType]):
|
|||||||
if current_value != value or first_set:
|
if current_value != value or first_set:
|
||||||
setattr(obj, f"__first_set_{self.internal_name}", False)
|
setattr(obj, f"__first_set_{self.internal_name}", False)
|
||||||
setattr(obj, self.internal_name, value)
|
setattr(obj, self.internal_name, value)
|
||||||
self.check_watchers(obj, name, current_value)
|
self._check_watchers(obj, name, current_value)
|
||||||
if self._layout or self._repaint:
|
if self._layout or self._repaint:
|
||||||
obj.refresh(repaint=self._repaint, layout=self._layout)
|
obj.refresh(repaint=self._repaint, layout=self._layout)
|
||||||
|
|
||||||
@classmethod
|
@classmethod
|
||||||
def check_watchers(cls, obj: Reactable, name: str, old_value: Any) -> None:
|
def _check_watchers(cls, obj: Reactable, name: str, old_value: Any) -> None:
|
||||||
|
|
||||||
internal_name = f"_reactive_{name}"
|
internal_name = f"_reactive_{name}"
|
||||||
value = getattr(obj, internal_name)
|
value = getattr(obj, internal_name)
|
||||||
@@ -158,7 +149,7 @@ class Reactive(Generic[ReactiveType]):
|
|||||||
watch_result = watch_function(value)
|
watch_result = watch_function(value)
|
||||||
if isawaitable(watch_result):
|
if isawaitable(watch_result):
|
||||||
await watch_result
|
await watch_result
|
||||||
await Reactive.compute(obj)
|
await Reactive._compute(obj)
|
||||||
|
|
||||||
watch_function = getattr(obj, f"watch_{name}", None)
|
watch_function = getattr(obj, f"watch_{name}", None)
|
||||||
if callable(watch_function):
|
if callable(watch_function):
|
||||||
@@ -182,7 +173,7 @@ class Reactive(Generic[ReactiveType]):
|
|||||||
)
|
)
|
||||||
|
|
||||||
@classmethod
|
@classmethod
|
||||||
async def compute(cls, obj: Reactable) -> None:
|
async def _compute(cls, obj: Reactable) -> None:
|
||||||
_rich_traceback_guard = True
|
_rich_traceback_guard = True
|
||||||
computes = getattr(obj, "__computes", [])
|
computes = getattr(obj, "__computes", [])
|
||||||
for compute in computes:
|
for compute in computes:
|
||||||
@@ -203,4 +194,4 @@ def watch(
|
|||||||
setattr(obj, watcher_name, set())
|
setattr(obj, watcher_name, set())
|
||||||
watchers = getattr(obj, watcher_name)
|
watchers = getattr(obj, watcher_name)
|
||||||
watchers.add(callback)
|
watchers.add(callback)
|
||||||
Reactive.check_watchers(obj, attribute_name, current_value)
|
Reactive._check_watchers(obj, attribute_name, current_value)
|
||||||
|
|||||||
Reference in New Issue
Block a user