Commit 56d9513
authored
bfcacheId: Opt out of state preservation (vercel#93633)
When `cacheComponents` is enabled, the App Router preserves state across
navigations by rendering inactive routes inside React `<Activity>`
boundaries.
As a default behavior, this is a huge convenience because it lets you
navigate between routes without resetting or losing ephemeral UI state
(scroll position, expand/collapse, in-progress form edits). Previously
the only way to do this was to explicitly track each state with an
external state manager, or hoist it to a parent component.
It's still the often the case that you should be explicitly tracking all
important UI state, anyway, so that it survives a hard refresh of the
app, or the browser window being accidentally closed. For example, forms
draft states should be persisted to a server-side database or local
storage engine. If you're already doing that, then it doesn't matter so
much whether client state is preserved via `<Activity>` boundaries or
not.
For the long tail of ephemeral state that is not tracked, Next.js's
philosophy is that it's a better UX default to preserve as much
emphemeral state as possible. It's easier to model the cases where you
_do_ want state to be reset on navigation as exceptions, compared to the
other way around.
However, this is a significant change compared to the pre-Cache
Components previous behavior of Next.js, and compared to other web
frameworks, and indeed the browser's own native bfcache (which
implements state restoration for history traversal navigations only, not
push/replace).
There's are also lots of existing codebases that may rely on the current
behavior, and may break subtly under these new semantics. Even if this
new default unlocks better UX patterns, we don't want to force everyone
to migrate all their code all at once.
So, this PR introduces a drop-in mechanism for opting out of state
preservation when navigating to a previously visited route.
The API is exposed as `useRouter().bfcacheId`. It's intended to be
passed to a React `key`:
<form key={useRouter().bfcacheId}>
The id is contextual: read from a layout, you get the layout's id; read
from a page, you get the page's id. It's stable across back/forward
navigations, `router.refresh()`, server actions that call `refresh()`,
and search-param- or hash-only navigations — i.e., any time the
surrounding segment is preserved. It changes when the segment is freshly
created by a push or replace into a different route.
An important detail is that the previous id is restored during a back/
foward navigation. So state preservation will still work if you navigate
via the browser's back button.
Why add this to `useRouter()` instead of giving it its own hook? The
intent is communicate that `bfcacheId` is not considered an idiomatic
pattern — the recommended fix for "I want this state to reset on
navigation" is almost always something else: an explicit reset in a
submit handler, or a key derived from the underlying data (e.g., a draft
id from the server). `useRouter` is the hook where we expose low-level
APIs that are supported but are only recommended for advanced or
exceptional cases. (For example, instead of `router.push()`, you should
almost always use a `<Link>` component instead.)1 parent 63cd423 commit 56d9513
17 files changed
Lines changed: 564 additions & 25 deletions
File tree
- docs/01-app/03-api-reference/04-functions
- packages/next/src
- client/components
- router-reducer
- segment-cache
- test/e2e/app-dir/use-router-bfcache-id
- app
- [group]
- [page]
- components
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
| |||
47 | 47 | | |
48 | 48 | | |
49 | 49 | | |
| 50 | + | |
50 | 51 | | |
51 | 52 | | |
52 | 53 | | |
| |||
156 | 157 | | |
157 | 158 | | |
158 | 159 | | |
| 160 | + | |
| 161 | + | |
| 162 | + | |
| 163 | + | |
| 164 | + | |
| 165 | + | |
| 166 | + | |
| 167 | + | |
| 168 | + | |
| 169 | + | |
| 170 | + | |
| 171 | + | |
| 172 | + | |
| 173 | + | |
| 174 | + | |
| 175 | + | |
| 176 | + | |
| 177 | + | |
| 178 | + | |
| 179 | + | |
| 180 | + | |
| 181 | + | |
159 | 182 | | |
160 | 183 | | |
161 | 184 | | |
| |||
Lines changed: 3 additions & 0 deletions
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
| |||
495 | 495 | | |
496 | 496 | | |
497 | 497 | | |
| 498 | + | |
| 499 | + | |
| 500 | + | |
498 | 501 | | |
499 | 502 | | |
500 | 503 | | |
| |||
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
| |||
179 | 179 | | |
180 | 180 | | |
181 | 181 | | |
182 | | - | |
| 182 | + | |
| 183 | + | |
| 184 | + | |
| 185 | + | |
| 186 | + | |
| 187 | + | |
| 188 | + | |
| 189 | + | |
| 190 | + | |
| 191 | + | |
| 192 | + | |
| 193 | + | |
| 194 | + | |
| 195 | + | |
| 196 | + | |
| 197 | + | |
| 198 | + | |
| 199 | + | |
| 200 | + | |
| 201 | + | |
| 202 | + | |
| 203 | + | |
| 204 | + | |
183 | 205 | | |
184 | 206 | | |
185 | 207 | | |
| |||
Lines changed: 119 additions & 21 deletions
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
| |||
245 | 245 | | |
246 | 246 | | |
247 | 247 | | |
248 | | - | |
| 248 | + | |
| 249 | + | |
| 250 | + | |
| 251 | + | |
249 | 252 | | |
250 | 253 | | |
251 | | - | |
| 254 | + | |
| 255 | + | |
252 | 256 | | |
253 | 257 | | |
254 | 258 | | |
| |||
347 | 351 | | |
348 | 352 | | |
349 | 353 | | |
350 | | - | |
| 354 | + | |
| 355 | + | |
| 356 | + | |
| 357 | + | |
| 358 | + | |
351 | 359 | | |
352 | 360 | | |
353 | 361 | | |
| |||
364 | 372 | | |
365 | 373 | | |
366 | 374 | | |
367 | | - | |
| 375 | + | |
| 376 | + | |
| 377 | + | |
| 378 | + | |
| 379 | + | |
| 380 | + | |
| 381 | + | |
368 | 382 | | |
369 | 383 | | |
370 | 384 | | |
371 | 385 | | |
372 | | - | |
373 | | - | |
374 | | - | |
375 | | - | |
376 | | - | |
377 | | - | |
378 | | - | |
| 386 | + | |
| 387 | + | |
| 388 | + | |
| 389 | + | |
| 390 | + | |
| 391 | + | |
| 392 | + | |
| 393 | + | |
| 394 | + | |
| 395 | + | |
| 396 | + | |
| 397 | + | |
| 398 | + | |
| 399 | + | |
| 400 | + | |
| 401 | + | |
| 402 | + | |
379 | 403 | | |
380 | 404 | | |
381 | 405 | | |
| |||
636 | 660 | | |
637 | 661 | | |
638 | 662 | | |
639 | | - | |
| 663 | + | |
| 664 | + | |
| 665 | + | |
| 666 | + | |
640 | 667 | | |
641 | 668 | | |
642 | 669 | | |
| |||
879 | 906 | | |
880 | 907 | | |
881 | 908 | | |
| 909 | + | |
| 910 | + | |
882 | 911 | | |
883 | 912 | | |
884 | 913 | | |
885 | 914 | | |
886 | 915 | | |
| 916 | + | |
887 | 917 | | |
888 | 918 | | |
889 | 919 | | |
| |||
895 | 925 | | |
896 | 926 | | |
897 | 927 | | |
898 | | - | |
| 928 | + | |
| 929 | + | |
899 | 930 | | |
900 | 931 | | |
901 | 932 | | |
| |||
927 | 958 | | |
928 | 959 | | |
929 | 960 | | |
| 961 | + | |
| 962 | + | |
| 963 | + | |
| 964 | + | |
930 | 965 | | |
931 | 966 | | |
932 | 967 | | |
933 | 968 | | |
934 | 969 | | |
935 | | - | |
| 970 | + | |
| 971 | + | |
936 | 972 | | |
937 | 973 | | |
938 | 974 | | |
| |||
967 | 1003 | | |
968 | 1004 | | |
969 | 1005 | | |
970 | | - | |
| 1006 | + | |
| 1007 | + | |
971 | 1008 | | |
972 | 1009 | | |
973 | 1010 | | |
974 | 1011 | | |
975 | 1012 | | |
976 | 1013 | | |
977 | 1014 | | |
978 | | - | |
| 1015 | + | |
| 1016 | + | |
979 | 1017 | | |
980 | 1018 | | |
981 | 1019 | | |
982 | | - | |
| 1020 | + | |
| 1021 | + | |
| 1022 | + | |
| 1023 | + | |
| 1024 | + | |
| 1025 | + | |
| 1026 | + | |
983 | 1027 | | |
984 | 1028 | | |
985 | 1029 | | |
| |||
1000 | 1044 | | |
1001 | 1045 | | |
1002 | 1046 | | |
| 1047 | + | |
| 1048 | + | |
| 1049 | + | |
1003 | 1050 | | |
1004 | 1051 | | |
1005 | 1052 | | |
1006 | 1053 | | |
1007 | 1054 | | |
1008 | | - | |
| 1055 | + | |
| 1056 | + | |
1009 | 1057 | | |
1010 | 1058 | | |
1011 | 1059 | | |
| |||
1208 | 1256 | | |
1209 | 1257 | | |
1210 | 1258 | | |
1211 | | - | |
| 1259 | + | |
| 1260 | + | |
1212 | 1261 | | |
1213 | 1262 | | |
1214 | 1263 | | |
1215 | 1264 | | |
1216 | 1265 | | |
1217 | 1266 | | |
1218 | 1267 | | |
1219 | | - | |
| 1268 | + | |
| 1269 | + | |
1220 | 1270 | | |
1221 | 1271 | | |
1222 | 1272 | | |
1223 | 1273 | | |
1224 | 1274 | | |
1225 | | - | |
| 1275 | + | |
1226 | 1276 | | |
1227 | 1277 | | |
1228 | 1278 | | |
| |||
1236 | 1286 | | |
1237 | 1287 | | |
1238 | 1288 | | |
| 1289 | + | |
1239 | 1290 | | |
1240 | 1291 | | |
1241 | 1292 | | |
| |||
1245 | 1296 | | |
1246 | 1297 | | |
1247 | 1298 | | |
| 1299 | + | |
| 1300 | + | |
| 1301 | + | |
| 1302 | + | |
| 1303 | + | |
| 1304 | + | |
| 1305 | + | |
| 1306 | + | |
| 1307 | + | |
| 1308 | + | |
| 1309 | + | |
| 1310 | + | |
| 1311 | + | |
| 1312 | + | |
| 1313 | + | |
| 1314 | + | |
| 1315 | + | |
| 1316 | + | |
| 1317 | + | |
| 1318 | + | |
| 1319 | + | |
| 1320 | + | |
| 1321 | + | |
| 1322 | + | |
| 1323 | + | |
| 1324 | + | |
| 1325 | + | |
| 1326 | + | |
| 1327 | + | |
| 1328 | + | |
| 1329 | + | |
| 1330 | + | |
| 1331 | + | |
| 1332 | + | |
| 1333 | + | |
| 1334 | + | |
| 1335 | + | |
| 1336 | + | |
| 1337 | + | |
| 1338 | + | |
| 1339 | + | |
| 1340 | + | |
| 1341 | + | |
| 1342 | + | |
| 1343 | + | |
| 1344 | + | |
1248 | 1345 | | |
| 1346 | + | |
1249 | 1347 | | |
1250 | 1348 | | |
1251 | 1349 | | |
| |||
Lines changed: 21 additions & 3 deletions
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
| |||
34 | 34 | | |
35 | 35 | | |
36 | 36 | | |
| 37 | + | |
| 38 | + | |
| 39 | + | |
| 40 | + | |
| 41 | + | |
37 | 42 | | |
38 | 43 | | |
39 | 44 | | |
| |||
64 | 69 | | |
65 | 70 | | |
66 | 71 | | |
67 | | - | |
| 72 | + | |
| 73 | + | |
68 | 74 | | |
69 | 75 | | |
70 | 76 | | |
| |||
79 | 85 | | |
80 | 86 | | |
81 | 87 | | |
| 88 | + | |
| 89 | + | |
82 | 90 | | |
83 | 91 | | |
84 | 92 | | |
| |||
104 | 112 | | |
105 | 113 | | |
106 | 114 | | |
107 | | - | |
| 115 | + | |
| 116 | + | |
108 | 117 | | |
109 | 118 | | |
110 | | - | |
| 119 | + | |
| 120 | + | |
| 121 | + | |
| 122 | + | |
| 123 | + | |
| 124 | + | |
| 125 | + | |
| 126 | + | |
| 127 | + | |
| 128 | + | |
111 | 129 | | |
112 | 130 | | |
113 | 131 | | |
| |||
0 commit comments