Skip to content

Commit 0207c2f

Browse files
committed
allow for optional re-rendering on login/logout methods
1 parent 833d335 commit 0207c2f

File tree

3 files changed

+42
-14
lines changed

3 files changed

+42
-14
lines changed

src/reactpy_django/auth/components.py

Lines changed: 21 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -19,25 +19,40 @@
1919

2020

2121
@component
22-
def session_manager(child: Any):
22+
def root_manager(child: Any):
23+
scope = hooks.use_connection().scope
24+
_, set_rerender = hooks.use_state(uuid4)
25+
26+
@hooks.use_effect(dependencies=[])
27+
def setup_asgi_scope():
28+
"""Store trigger functions in the websocket scope so that ReactPy-Django's hooks can command
29+
any relevant actions."""
30+
scope["reactpy"]["rerender"] = rerender
31+
32+
async def rerender():
33+
"""Event that can force a rerender of the entire component tree."""
34+
set_rerender(uuid4())
35+
36+
return child
37+
38+
39+
@component
40+
def session_manager():
2341
"""This component can force the client (browser) to switch HTTP sessions,
2442
making it match the websocket session.
2543
2644
Used to force persistent authentication between Django's websocket and HTTP stack."""
2745
from reactpy_django import config
2846

2947
synchronize_requested, set_synchronize_requested = hooks.use_state(False)
30-
_, set_rerender = hooks.use_state(uuid4)
3148
uuid = hooks.use_ref("")
3249
scope = hooks.use_connection().scope
3350

3451
@hooks.use_effect(dependencies=[])
3552
def setup_asgi_scope():
3653
"""Store trigger functions in the websocket scope so that ReactPy-Django's hooks can command
3754
any relevant actions."""
38-
scope.setdefault("reactpy", {})
3955
scope["reactpy"]["synchronize_session"] = synchronize_session
40-
scope["reactpy"]["rerender"] = rerender
4156

4257
@hooks.use_effect(dependencies=[synchronize_requested])
4358
async def synchronize_session_watchdog():
@@ -86,15 +101,10 @@ async def synchronize_session_callback(status_code: int, response: str):
86101
f"Client returned unexpected HTTP status code ({status_code}) while trying to sychronize sessions.",
87102
)
88103

89-
async def rerender():
90-
"""Event that can force a rerender of the entire component tree."""
91-
set_rerender(uuid4())
92-
93104
# If needed, synchronize sessions by configuring all relevant session cookies.
94105
# This is achieved by commanding the client to perform a HTTP request to our session manager endpoint.
95-
http_request = None
96106
if synchronize_requested:
97-
http_request = HttpRequest(
107+
return HttpRequest(
98108
{
99109
"method": "GET",
100110
"url": reverse("reactpy:session_manager", args=[uuid.current]),
@@ -103,4 +113,4 @@ async def rerender():
103113
},
104114
)
105115

106-
return html._(child, http_request)
116+
return None

src/reactpy_django/hooks.py

Lines changed: 14 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -423,14 +423,27 @@ def use_auth():
423423

424424
scope = use_scope()
425425

426-
async def login(user: AbstractUser):
426+
async def login(user: AbstractUser, rerender: bool = True):
427+
"""Login a user.
428+
429+
Args:
430+
user: The user to login.
431+
rerender: If True, the root component will be re-rendered after the user is logged in."""
427432
await channels_auth.login(scope, user, backend=config.REACTPY_AUTH_BACKEND)
428433
session_save_method = getattr(scope["session"], "asave", scope["session"].save)
429434
await ensure_async(session_save_method)()
430435
await scope["reactpy"]["synchronize_session"]()
431436

437+
if rerender:
438+
await scope["reactpy"]["rerender"]()
439+
432440
async def logout(rerender: bool = True):
441+
"""Logout the current user.
442+
443+
Args:
444+
rerender: If True, the root component will be re-rendered after the user is logged out."""
433445
await channels_auth.logout(scope)
446+
434447
if rerender:
435448
await scope["reactpy"]["rerender"]()
436449

src/reactpy_django/websocket/consumer.py

Lines changed: 7 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -142,8 +142,9 @@ async def encode_json(cls, content):
142142

143143
async def run_dispatcher(self):
144144
"""Runs the main loop that performs component rendering tasks."""
145+
# TODO: Figure out why exceptions raised in this method are not being printed to the console.
145146
from reactpy_django import models
146-
from reactpy_django.auth.components import session_manager
147+
from reactpy_django.auth.components import root_manager, session_manager
147148
from reactpy_django.config import (
148149
REACTPY_REGISTERED_COMPONENTS,
149150
REACTPY_SESSION_MAX_AGE,
@@ -212,7 +213,11 @@ async def run_dispatcher(self):
212213
with contextlib.suppress(Exception):
213214
await serve_layout(
214215
Layout( # type: ignore
215-
ConnectionContext(session_manager(root_component), value=connection)
216+
ConnectionContext(
217+
session_manager(),
218+
root_manager(root_component),
219+
value=connection,
220+
)
216221
),
217222
self.send_json,
218223
self.recv_queue.get,

0 commit comments

Comments
 (0)