Skip to content

Commit cac297b

Browse files
committed
Better fix for key identity of route components
1 parent 491027d commit cac297b

File tree

1 file changed

+18
-5
lines changed

1 file changed

+18
-5
lines changed

src/reactpy_router/routers.py

Lines changed: 18 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -4,13 +4,12 @@
44

55
from dataclasses import replace
66
from logging import getLogger
7-
from typing import Any, Iterator, Literal, Sequence
7+
from typing import Any, Iterator, Literal, Sequence, cast
88

99
from reactpy import component, use_memo, use_state
1010
from reactpy.backend.hooks import ConnectionContext, use_connection
1111
from reactpy.backend.types import Connection, Location
12-
from reactpy.core.types import VdomDict
13-
from reactpy.types import ComponentType
12+
from reactpy.types import ComponentType, VdomDict
1413

1514
from reactpy_router.components import History
1615
from reactpy_router.hooks import _route_state_context, _RouteState
@@ -86,6 +85,18 @@ def _iter_routes(routes: Sequence[RouteType]) -> Iterator[RouteType]:
8685
yield parent
8786

8887

88+
def _add_route_key(match: tuple[Any, dict[str, Any]], key: str | int) -> Any:
89+
"""Add a key to the VDOM or component on the current route, if it doesn't already have one."""
90+
element, _params = match
91+
if hasattr(element, "render") and not element.key:
92+
element = cast(ComponentType, element)
93+
element.key = key
94+
elif isinstance(element, dict) and not element.get("key", None):
95+
element = cast(VdomDict, element)
96+
element["key"] = key
97+
return match
98+
99+
89100
def _match_route(
90101
compiled_routes: Sequence[CompiledRoute],
91102
location: Location,
@@ -97,12 +108,14 @@ def _match_route(
97108
match = resolver.resolve(location.pathname)
98109
if match is not None:
99110
if select == "first":
100-
return [match]
111+
return [_add_route_key(match, resolver.key)]
101112

102113
# Matching multiple routes is disabled since `react-router` no longer supports multiple
103114
# matches via the `Route` component. However, it's kept here to support future changes
104115
# or third-party routers.
105-
matches.append(match) # pragma: no cover
116+
# TODO: The `resolver.key` value has edge cases where it is not unique enough to use as
117+
# a key here, unless we begin throwing errors for duplicate routes.
118+
matches.append(_add_route_key(match, resolver.key)) # pragma: no cover
106119

107120
if not matches:
108121
_logger.debug("No matching route found for %s", location.pathname)

0 commit comments

Comments
 (0)