Skip to content

Commit 491027d

Browse files
committed
functional navigate component
1 parent a4e90aa commit 491027d

File tree

4 files changed

+61
-16
lines changed

4 files changed

+61
-16
lines changed

src/js/src/index.js

Lines changed: 29 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -12,13 +12,13 @@ export function bind(node) {
1212
};
1313
}
1414

15-
export function History({ onHistoryChange }) {
15+
export function History({ onHistoryChangeCallback }) {
1616
// Capture browser "history go back" action and tell the server about it
1717
// Note: Browsers do not allow us to detect "history go forward" actions.
1818
React.useEffect(() => {
1919
// Register a listener for the "popstate" event and send data back to the server using the `onHistoryChange` callback.
2020
const listener = () => {
21-
onHistoryChange({
21+
onHistoryChangeCallback({
2222
pathname: window.location.pathname,
2323
search: window.location.search,
2424
});
@@ -34,29 +34,29 @@ export function History({ onHistoryChange }) {
3434
// Tell the server about the URL during the initial page load
3535
// FIXME: This currently runs every time any component is mounted due to a ReactPy core rendering bug.
3636
// https://github.com/reactive-python/reactpy/pull/1224
37-
React.useEffect(() => {
38-
onHistoryChange({
39-
pathname: window.location.pathname,
40-
search: window.location.search,
41-
});
42-
return () => {};
43-
}, []);
37+
// React.useEffect(() => {
38+
// onHistoryChange({
39+
// pathname: window.location.pathname,
40+
// search: window.location.search,
41+
// });
42+
// return () => {};
43+
// }, []);
4444
return null;
4545
}
4646

4747
// FIXME: The Link component is unused due to a ReactPy core rendering bug
4848
// which causes duplicate rendering (and thus duplicate event listeners).
4949
// https://github.com/reactive-python/reactpy/pull/1224
50-
export function Link({ onClick, linkClass }) {
50+
export function Link({ onClickCallback, linkClass }) {
5151
// This component is not the actual anchor link.
5252
// It is an event listener for the link component created by ReactPy.
5353
React.useEffect(() => {
5454
// Event function that will tell the server about clicks
5555
const handleClick = (event) => {
5656
event.preventDefault();
5757
let to = event.target.getAttribute("href");
58-
window.history.pushState({}, to, new URL(to, window.location));
59-
onClick({
58+
window.history.pushState(null, "", new URL(to, window.location));
59+
onClickCallback({
6060
pathname: window.location.pathname,
6161
search: window.location.search,
6262
});
@@ -78,3 +78,20 @@ export function Link({ onClick, linkClass }) {
7878
});
7979
return null;
8080
}
81+
82+
export function Navigate({ onNavigateCallback, to, replace }) {
83+
React.useEffect(() => {
84+
if (replace) {
85+
window.history.replaceState(null, "", new URL(to, window.location));
86+
} else {
87+
window.history.pushState(null, "", new URL(to, window.location));
88+
}
89+
onNavigateCallback({
90+
pathname: window.location.pathname,
91+
search: window.location.search,
92+
});
93+
return () => {};
94+
}, []);
95+
96+
return null;
97+
}

src/reactpy_router/__init__.py

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,7 @@
22
__version__ = "0.1.1"
33

44

5-
from .components import link, route
5+
from .components import link, navigate, route
66
from .hooks import use_params, use_search_params
77
from .routers import browser_router, create_router
88

@@ -13,4 +13,5 @@
1313
"browser_router",
1414
"use_params",
1515
"use_search_params",
16+
"navigate",
1617
)

src/reactpy_router/components.py

Lines changed: 29 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -26,6 +26,12 @@
2626
)
2727
"""Client-side portion of link handling"""
2828

29+
Navigate = export(
30+
module_from_file("reactpy-router", file=Path(__file__).parent / "static" / "bundle.js"),
31+
("Navigate"),
32+
)
33+
"""Client-side portion of the navigate component"""
34+
2935
link_js_content = (Path(__file__).parent / "static" / "link.js").read_text(encoding="utf-8")
3036

3137

@@ -93,11 +99,32 @@ def on_click(_event: dict[str, Any]) -> None:
9399

94100
return html._(html.a(attrs, *children), html.script(link_js_content.replace("UUID", uuid_string)))
95101

96-
# def on_click(_event: dict[str, Any]) -> None:
102+
# def on_click_callback(_event: dict[str, Any]) -> None:
97103
# set_location(Location(**_event))
98-
# return html._(html.a(attrs, *children), Link({"onClick": on_click, "linkClass": uuid_string}))
104+
# return html._(html.a(attrs, *children), Link({"onClickCallback": on_click_callback, "linkClass": uuid_string}))
99105

100106

101107
def route(path: str, element: Any | None, *routes: Route) -> Route:
102108
"""Create a route with the given path, element, and child routes."""
103109
return Route(path, element, routes)
110+
111+
112+
def navigate(to: str, replace: bool = False) -> Component:
113+
"""A `navigate` element changes the current location when it is rendered."""
114+
return _navigate(to, replace)
115+
116+
117+
@component
118+
def _navigate(to: str, replace: bool = False) -> VdomDict | None:
119+
"""A `navigate` element changes the current location when it is rendered."""
120+
location = use_connection().location
121+
set_location = _use_route_state().set_location
122+
pathname = to.split("?", 1)[0]
123+
124+
def on_navigate_callback(_event: dict[str, Any]) -> None:
125+
set_location(Location(**_event))
126+
127+
if location.pathname != pathname:
128+
return Navigate({"onNavigateCallback": on_navigate_callback, "to": to, "replace": replace})
129+
130+
return None

src/reactpy_router/routers.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -71,7 +71,7 @@ def on_history_change(event: dict[str, Any]) -> None:
7171
set_location(new_location)
7272

7373
return ConnectionContext(
74-
History({"onHistoryChange": on_history_change}), # type: ignore[return-value]
74+
History({"onHistoryChangeCallback": on_history_change}), # type: ignore[return-value]
7575
*route_elements,
7676
value=Connection(old_conn.scope, location, old_conn.carrier),
7777
)

0 commit comments

Comments
 (0)