You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
{{ message }}
Repository navigation
Commit 27c4c57
Browse filesBrowse the repository at this point in the historyBrowse files
Add use_session_state hook for persistent state across WebSocket reconnects (#300)
Add a dedicated, database-backed hook `reactpy_django.hooks.use_session_state(default, key)` that persists state so it survives WebSocket reconnects (and, optionally, page reloads).
Copy file name to clipboardExpand all lines: CHANGELOG.md
+7-1Lines changed: 7 additions & 1 deletion
Display the source diff
Display the rich diff
Original file line number
Diff line number
Diff line change
@@ -21,6 +21,12 @@ Don't forget to remove deprecated code on each major release!
21
21
22
22
### Added
23
23
24
+
- Add `reactpy_django.hooks.use_session_state` hook for persistent state across WebSocket reconnects.
25
+
- State is stored in the ReactPy database, so it survives multi-process deployments and round-robin load balancing across hosts.
26
+
-`settings.py:REACTPY_SESSION_STATE_MODE` to control whether state is scoped per-tab (default) or per-user.
27
+
-`settings.py:REACTPY_SESSION_STATE_SYNC_INTERVAL` (default 10 seconds) to control how frequently state is flushed to the database. Set to `0` to disable periodic syncing so state is only persisted on unmount.
28
+
-`settings.py:REACTPY_SESSION_STATE_MAX_AGE` to control how long stale session state is retained.
29
+
-`settings.py:REACTPY_CLEAN_SESSION_STATE` to control whether stale session state is cleaned up during automatic cleanups.
24
30
- Automatically serve ReactPy wheel from Django's static directory when using PyScript.
25
31
26
32
### Changed
@@ -444,7 +450,7 @@ Don't forget to remove deprecated code on each major release!
444
450
### Fixed
445
451
446
452
- Change type hint on `view_to_component`callable to have `request` argument be optional.
447
-
- Change type hint on `view_to_component` to represent it as a decorator with parenthesis (such as`@view_to_component(compatibility=True)`)
453
+
- Change type hint on `view_to_component` to represent it as a decorator with parenthesis (such as`@view_to_component(compatibility=True)`).
Copy file name to clipboardExpand all lines: docs/src/reference/hooks.md
+41Lines changed: 41 additions & 0 deletions
Display the source diff
Display the rich diff
Original file line number
Diff line number
Diff line change
@@ -385,6 +385,47 @@ User data saved with this hook is stored within the `#!python REACTPY_DATABASE`.
385
385
386
386
---
387
387
388
+
### Use Session State
389
+
390
+
Persist state across WebSocket reconnects (and, optionally, page reloads) so that it survives a fresh `#!python Layout` being created on reconnect.
391
+
392
+
This hook stores its value in the `#!python REACTPY_DATABASE`, so it is more robust than in-memory state because it survives multi-process deployments and round-robin load balancing across multiple hosts.
393
+
394
+
=== "components.py"
395
+
396
+
```python
397
+
{% include "../../examples/python/use_session_state.py" %}
398
+
```
399
+
400
+
??? example "See Interface"
401
+
402
+
<font size="4">**Parameters**</font>
403
+
404
+
| Name | Type | Description | Default |
405
+
| --- | --- | --- | --- |
406
+
| `#!python default` | `#!python Any` | The value to use when no persisted state exists. | N/A |
407
+
| `#!python key` | `#!python str` | A unique identifier for this state slot within the computed scope. Multiple `#!python use_session_state` hooks in the same component must use distinct keys. | N/A |
408
+
| `#!python save_default` | `#!python bool` | If `#!python True`, the `#!python default` value will be persisted when no state already exists in the database. | `#!python False` |
409
+
410
+
<font size="4">**Returns**</font>
411
+
412
+
| Type | Description |
413
+
| --- | --- |
414
+
| `#!python tuple[Any, Callable[[Any], None]]` | A tuple of `#!python (state, set_state)`. `#!python state` is the current value (loaded from the database, or `#!python default` if none exists). `#!python set_state` updates the in-memory value immediately and schedules a debounced database write so that frequently-changing values do not hammer the database. The update interval is controlled by `#!python REACTPY_SESSION_STATE_SYNC_INTERVAL`; setting it to `#!python 0` disables periodic syncing so writes only occur on unmount. |
415
+
416
+
??? question "How is state scoped?"
417
+
418
+
The state's scope is controlled by the `#!python REACTPY_SESSION_STATE_MODE` [setting](./settings.md#reactpy_session_state_mode).
419
+
420
+
- `#!python "tab"` (default): state is scoped to the rendered component (a per-tab, per-component token that is stable across reconnects). This works for anonymous users without requiring `#!python django.contrib.sessions`, and isolates state between browser tabs.
421
+
- `#!python "user"`: state is scoped to the authenticated user, falling back to a per-tab token for anonymous users.
422
+
423
+
??? warning "Only serializable data may be stored"
424
+
425
+
Values are serialized with `#!python dill`, so most common Python objects are supported, but objects holding resources that are not picklable (e.g. open file handles or network connections) will fail.
Controls the scope of state persisted by the [`use_session_state`](./hooks.md#use-session-state) hook.
208
+
209
+
-`#!python "tab"` (default): state is scoped to the rendered component (a per-tab, per-component token that is stable across WebSocket reconnects). This works for anonymous users without requiring `#!python django.contrib.sessions`, and isolates state between browser tabs.
210
+
-`#!python "user"`: state is scoped to the authenticated user, falling back to a per-tab token for anonymous users.
Seconds between debounced database flush writes for `#!python use_session_state`. Rapid state changes (e.g. typing) are coalesced into a single database write after this interval elapses.
221
+
222
+
Set this value to `#!python 0` to disable periodic syncing. In that case, state is only persisted to the database when the component is unmounted (such as when a WebSocket reconnects).
0 commit comments