File tree 4 files changed +115
-6
lines changed
packages/next/src/client/components
test/e2e/app-dir/navigation
pages/search-params-pages/[foo]
4 files changed +115
-6
lines changed Original file line number Diff line number Diff line change @@ -170,13 +170,15 @@ export function useParams<T extends Params = Params>(): T {
170
170
const globalLayoutRouter = useContext ( GlobalLayoutRouterContext )
171
171
const pathParams = useContext ( PathParamsContext )
172
172
173
- // When it's under app router
174
- if ( globalLayoutRouter ) {
175
- return getSelectedParams ( globalLayoutRouter . tree ) as T
176
- }
173
+ return useMemo ( ( ) => {
174
+ // When it's under app router
175
+ if ( globalLayoutRouter ?. tree ) {
176
+ return getSelectedParams ( globalLayoutRouter . tree ) as T
177
+ }
177
178
178
- // When it's under client side pages router
179
- return pathParams as T
179
+ // When it's under client side pages router
180
+ return pathParams as T
181
+ } , [ globalLayoutRouter ?. tree , pathParams ] )
180
182
}
181
183
182
184
// TODO-APP: handle parallel routes
Original file line number Diff line number Diff line change
1
+ 'use client'
2
+ import { useParams , useRouter } from 'next/navigation'
3
+ import { useState } from 'react'
4
+ import { useEffect } from 'react'
5
+
6
+ export default function Page ( ) {
7
+ const params = useParams ( )
8
+ const router = useRouter ( )
9
+ const [ count , setCount ] = useState ( 0 )
10
+ useEffect ( ( ) => {
11
+ console . log ( 'params changed' )
12
+ } , [ params ] )
13
+ return (
14
+ < div >
15
+ < button
16
+ id = "rerender-button"
17
+ onClick = { ( ) => setCount ( ( count ) => count + 1 ) }
18
+ >
19
+ Re-Render { count }
20
+ </ button >
21
+
22
+ < button
23
+ id = "change-params-button"
24
+ onClick = { ( ) => router . push ( '/search-params/bar' ) }
25
+ >
26
+ Change Params
27
+ </ button >
28
+ </ div >
29
+ )
30
+ }
Original file line number Diff line number Diff line change @@ -54,6 +54,54 @@ createNextDescribe(
54
54
: JSON . stringify ( requests )
55
55
} , 'success' )
56
56
} )
57
+
58
+ describe ( 'useParams identity between renders' , ( ) => {
59
+ async function runTests ( page : string ) {
60
+ const browser = await next . browser ( page )
61
+
62
+ await check (
63
+ async ( ) => JSON . stringify ( await browser . log ( ) ) ,
64
+ / p a r a m s c h a n g e d /
65
+ )
66
+
67
+ let outputIndex = ( await browser . log ( ) ) . length
68
+
69
+ await browser . elementById ( 'rerender-button' ) . click ( )
70
+ await browser . elementById ( 'rerender-button' ) . click ( )
71
+ await browser . elementById ( 'rerender-button' ) . click ( )
72
+
73
+ await check ( async ( ) => {
74
+ return browser . elementById ( 'rerender-button' ) . text ( )
75
+ } , 'Re-Render 3' )
76
+
77
+ await check ( async ( ) => {
78
+ const logs = await browser . log ( )
79
+ return JSON . stringify ( logs . slice ( outputIndex ) ) . includes (
80
+ 'params changed'
81
+ )
82
+ ? 'fail'
83
+ : 'success'
84
+ } , 'success' )
85
+
86
+ outputIndex = ( await browser . log ( ) ) . length
87
+
88
+ await browser . elementById ( 'change-params-button' ) . click ( )
89
+
90
+ await check (
91
+ async ( ) =>
92
+ JSON . stringify ( ( await browser . log ( ) ) . slice ( outputIndex ) ) ,
93
+ / p a r a m s c h a n g e d /
94
+ )
95
+ }
96
+
97
+ it ( 'should be stable in app' , async ( ) => {
98
+ await runTests ( '/search-params/foo' )
99
+ } )
100
+
101
+ it ( 'should be stable in pages' , async ( ) => {
102
+ await runTests ( '/search-params-pages/foo' )
103
+ } )
104
+ } )
57
105
} )
58
106
59
107
describe ( 'hash' , ( ) => {
Original file line number Diff line number Diff line change
1
+ import { useParams , useRouter } from 'next/navigation'
2
+ import { useState } from 'react'
3
+ import { useEffect } from 'react'
4
+
5
+ export default function Page ( ) {
6
+ const params = useParams ( )
7
+ const router = useRouter ( )
8
+ const [ count , setCount ] = useState ( 0 )
9
+ useEffect ( ( ) => {
10
+ console . log ( 'params changed' )
11
+ } , [ params ] )
12
+ return (
13
+ < div >
14
+ < button
15
+ id = "rerender-button"
16
+ onClick = { ( ) => setCount ( ( count ) => count + 1 ) }
17
+ >
18
+ Re-Render { count }
19
+ </ button >
20
+
21
+ < button
22
+ id = "change-params-button"
23
+ onClick = { ( ) => router . push ( '/search-params-pages/bar' ) }
24
+ >
25
+ Change Params
26
+ </ button >
27
+ </ div >
28
+ )
29
+ }
You can’t perform that action at this time.
0 commit comments