1414 * limitations under the License.
1515 */
1616
17- import { useMemo , useRef } from 'react'
17+ import { useEffect , useMemo , useRef } from 'react'
1818import { useLocation , useNavigate } from 'react-router-dom'
1919
2020import { getUrlWithSearchParams } from '@Common/Helper'
@@ -56,6 +56,10 @@ const useUrlFilters = <T = string, K = {}>({
5656
5757 const isAlreadyReadFromLocalStorage = useRef < boolean > ( false )
5858
59+ // Holds the search string to restore from local storage. The actual navigation
60+ // is deferred to an effect since react-router v6 disallows navigate() during render.
61+ const pendingLocalStorageSearch = useRef < string | null > ( null )
62+
5963 const getSearchParams = ( ) => {
6064 const locationSearchParams = new URLSearchParams ( location . search )
6165 if ( ! isAlreadyReadFromLocalStorage . current && localStorageKey ) {
@@ -67,8 +71,9 @@ const useUrlFilters = <T = string, K = {}>({
6771 const localSearchString = getUrlWithSearchParams ( '' , JSON . parse ( localStorageValue ) )
6872 const localSearchParams = new URLSearchParams ( localSearchString . split ( '?' ) [ 1 ] ?? '' )
6973
70- // This would remain replace since the initial value is being set from local storage
71- navigate ( { search : localSearchParams . toString ( ) } , { replace : true } )
74+ // Defer the navigation to an effect (see below). react-router v6 ignores
75+ // navigate() called during render. Returning the params here keeps the first render correct.
76+ pendingLocalStorageSearch . current = localSearchParams . toString ( )
7277 return localSearchParams
7378 } catch {
7479 localStorage . removeItem ( localStorageKey )
@@ -87,6 +92,17 @@ const useUrlFilters = <T = string, K = {}>({
8792
8893 const searchParams = getSearchParams ( )
8994
95+ // Apply the restored-from-local-storage search params to the URL after the initial render.
96+ // The value is only ever set during the first render, so this runs once on mount.
97+ useEffect ( ( ) => {
98+ if ( pendingLocalStorageSearch . current !== null ) {
99+ const search = pendingLocalStorageSearch . current
100+ pendingLocalStorageSearch . current = null
101+ // This remains replace since the initial value is being set from local storage
102+ navigate ( { search } , { replace : true } )
103+ }
104+ } , [ ] )
105+
90106 const getParsedSearchParams : UseUrlFiltersProps < T , K > [ 'parseSearchParams' ] = ( searchParamsToParse ) => {
91107 if ( parseSearchParams ) {
92108 return parseSearchParams ( searchParamsToParse )
0 commit comments