@finos/legend-application 16.0.91 → 16.0.93

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -1 +1 @@
1
- {"version":3,"file":"LegendApplicationNavigation.d.ts","sourceRoot":"","sources":["../../src/__lib__/LegendApplicationNavigation.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;GAcG;AAIH,oBAAY,8BAA8B;IACxC,mBAAmB,sBAAsB;CAC1C;AAED;;GAEG;AACH,eAAO,MAAM,6DAA6D,GACxE,sBAAsB,MAAM,EAC5B,SAAS,MAAM,EACf,YAAY,MAAM,EAClB,WAAW,MAAM,EACjB,YAAY,MAAM,GAAG,SAAS,KAC7B,MAK8C,CAAC;AAElD;;GAEG;AACH,eAAO,MAAM,uDAAuD,GAClE,wBAAwB,MAAM,EAC9B,YAAY,MAAM,KACjB,MAGE,CAAC;AAEN;;GAEG;AACH,eAAO,MAAM,2DAA2D,GACtE,wBAAwB,MAAM,EAC9B,iBAAiB,MAAM,EACvB,iBAAiB,MAAM,KACtB,MACuI,CAAC"}
1
+ {"version":3,"file":"LegendApplicationNavigation.d.ts","sourceRoot":"","sources":["../../src/__lib__/LegendApplicationNavigation.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;GAcG;AAIH,oBAAY,8BAA8B;IACxC,mBAAmB,sBAAsB;CAC1C;AAED;;GAEG;AACH,eAAO,MAAM,6DAA6D,GACxE,sBAAsB,MAAM,EAC5B,SAAS,MAAM,EACf,YAAY,MAAM,EAClB,WAAW,MAAM,EACjB,YAAY,MAAM,GAAG,SAAS,KAC7B,MAK8C,CAAC;AAElD;;GAEG;AACH,eAAO,MAAM,uDAAuD,GAClE,wBAAwB,MAAM,EAC9B,YAAY,MAAM,KACjB,MAGE,CAAC;AAEN;;GAEG;AACH,eAAO,MAAM,2DAA2D,GACtE,wBAAwB,MAAM,EAC9B,iBAAiB,MAAM,EACvB,iBAAiB,MAAM,KACtB,MACwI,CAAC"}
@@ -29,5 +29,5 @@ export const EXTERNAL_APPLICATION_NAVIGATION__generateNewDataCubeUrl = (dataCube
29
29
  /**
30
30
  * @external_application_navigation This depends on Registry routing and is hardcoded so it's potentially brittle
31
31
  */
32
- export const EXTERNAL_APPLICATION_NAVIGATION__generateRegistryLineageUrl = (registryApplicationUrl, dataProductName, accessPointName) => `${registryApplicationUrl}#/lineage/lakehouse/dataProduct/${dataProductName.toUpperCase()}/accessPoint/${accessPointName.toUpperCase()}`;
32
+ export const EXTERNAL_APPLICATION_NAVIGATION__generateRegistryLineageUrl = (registryApplicationUrl, dataProductName, accessPointName) => `${registryApplicationUrl}/#/lineage/lakehouse/dataProduct/${dataProductName.toUpperCase()}/accessPoint/${accessPointName.toUpperCase()}`;
33
33
  //# sourceMappingURL=LegendApplicationNavigation.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"LegendApplicationNavigation.js","sourceRoot":"","sources":["../../src/__lib__/LegendApplicationNavigation.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;GAcG;AAEH,OAAO,EAAE,sBAAsB,EAAE,MAAM,uBAAuB,CAAC;AAE/D,MAAM,CAAN,IAAY,8BAEX;AAFD,WAAY,8BAA8B;IACxC,2EAAyC,CAAA;AAC3C,CAAC,EAFW,8BAA8B,KAA9B,8BAA8B,QAEzC;AAED;;GAEG;AACH,MAAM,CAAC,MAAM,6DAA6D,GAAG,CAC3E,oBAA4B,EAC5B,OAAe,EACf,UAAkB,EAClB,SAAiB,EACjB,UAA8B,EACtB,EAAE,CACV,GAAG,oBAAoB,iBAAiB,sBAAsB,CAC5D,OAAO,EACP,UAAU,EACV,SAAS,CACV,GAAG,UAAU,CAAC,CAAC,CAAC,WAAW,UAAU,EAAE,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC;AAElD;;GAEG;AACH,MAAM,CAAC,MAAM,uDAAuD,GAAG,CACrE,sBAA8B,EAC9B,UAAkB,EACV,EAAE,CACV,GAAG,sBAAsB,eAAe,kBAAkB,CACxD,IAAI,CAAC,IAAI,CAAC,SAAS,CAAC,UAAU,CAAC,CAAC,CACjC,EAAE,CAAC;AAEN;;GAEG;AACH,MAAM,CAAC,MAAM,2DAA2D,GAAG,CACzE,sBAA8B,EAC9B,eAAuB,EACvB,eAAuB,EACf,EAAE,CACV,GAAG,sBAAsB,mCAAmC,eAAe,CAAC,WAAW,EAAE,gBAAgB,eAAe,CAAC,WAAW,EAAE,EAAE,CAAC"}
1
+ {"version":3,"file":"LegendApplicationNavigation.js","sourceRoot":"","sources":["../../src/__lib__/LegendApplicationNavigation.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;GAcG;AAEH,OAAO,EAAE,sBAAsB,EAAE,MAAM,uBAAuB,CAAC;AAE/D,MAAM,CAAN,IAAY,8BAEX;AAFD,WAAY,8BAA8B;IACxC,2EAAyC,CAAA;AAC3C,CAAC,EAFW,8BAA8B,KAA9B,8BAA8B,QAEzC;AAED;;GAEG;AACH,MAAM,CAAC,MAAM,6DAA6D,GAAG,CAC3E,oBAA4B,EAC5B,OAAe,EACf,UAAkB,EAClB,SAAiB,EACjB,UAA8B,EACtB,EAAE,CACV,GAAG,oBAAoB,iBAAiB,sBAAsB,CAC5D,OAAO,EACP,UAAU,EACV,SAAS,CACV,GAAG,UAAU,CAAC,CAAC,CAAC,WAAW,UAAU,EAAE,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC;AAElD;;GAEG;AACH,MAAM,CAAC,MAAM,uDAAuD,GAAG,CACrE,sBAA8B,EAC9B,UAAkB,EACV,EAAE,CACV,GAAG,sBAAsB,eAAe,kBAAkB,CACxD,IAAI,CAAC,IAAI,CAAC,SAAS,CAAC,UAAU,CAAC,CAAC,CACjC,EAAE,CAAC;AAEN;;GAEG;AACH,MAAM,CAAC,MAAM,2DAA2D,GAAG,CACzE,sBAA8B,EAC9B,eAAuB,EACvB,eAAuB,EACf,EAAE,CACV,GAAG,sBAAsB,oCAAoC,eAAe,CAAC,WAAW,EAAE,gBAAgB,eAAe,CAAC,WAAW,EAAE,EAAE,CAAC"}
package/lib/index.css CHANGED
@@ -1,4 +1,4 @@
1
- /** @license @finos/legend-application v16.0.91
1
+ /** @license @finos/legend-application v16.0.93
2
2
  * Copyright (c) 2020-present, Goldman Sachs
3
3
  *
4
4
  * Licensed under the Apache License, Version 2.0 (the "License");
package/lib/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@finos/legend-application",
3
- "version": "16.0.91",
3
+ "version": "16.0.93",
4
4
  "description": "Legend application core",
5
5
  "keywords": [
6
6
  "legend",
@@ -16,6 +16,13 @@
16
16
  import type { SetURLSearchParams } from 'react-router';
17
17
  /**
18
18
  * Util hook to keep a state variable in sync with a URL search parameter.
19
+ * This hook syncs from URL to state if the state is null/undefined (so
20
+ * initial value is set from URL) and from state to URL otherwise.
21
+ *
22
+ * This hook properly queues setSearchParams calls to ensure all updates
23
+ * are applied, working around react-router's limitation where multiple
24
+ * calls to setSearchParams in the same tick don't build on each other.
25
+ * See: https://github.com/remix-run/react-router/issues/9304
19
26
  *
20
27
  * @param stateVar the state variable to sync
21
28
  * @param updateStateVar setter function to update the state variable (should be memoized with useCallback)
@@ -24,5 +31,5 @@ import type { SetURLSearchParams } from 'react-router';
24
31
  * @param setSearchParams function to update the URL search parameters (i.e., from useSearchParams)
25
32
  * @param initializedCallback function to check if the underlying state is initialized and ready to sync with URL (should be memoized with useCallback)
26
33
  */
27
- export declare const useSyncStateAndSearchParam: (stateVar: string | boolean | number | null | undefined, updateStateVar: (val: string | null) => void, searchParamKey: string, searchParamValue: string | null, setSearchParams: SetURLSearchParams, initializedCallback: () => boolean) => void;
34
+ export declare const useSyncStateAndSearchParam: (stateVar: string | boolean | number | null | undefined, updateStateVar: (val: string | null) => void, searchParamKey: string, searchParamValue: string | null, setSearchParams: SetURLSearchParams, initializedCallback: () => boolean, clearParamOnUnmount?: boolean) => void;
28
35
  //# sourceMappingURL=URLUtils.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"URLUtils.d.ts","sourceRoot":"","sources":["../../src/util/URLUtils.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;GAcG;AAGH,OAAO,KAAK,EAAE,kBAAkB,EAAE,MAAM,cAAc,CAAC;AAEvD;;;;;;;;;GASG;AACH,eAAO,MAAM,0BAA0B,GACrC,UAAU,MAAM,GAAG,OAAO,GAAG,MAAM,GAAG,IAAI,GAAG,SAAS,EACtD,gBAAgB,CAAC,GAAG,EAAE,MAAM,GAAG,IAAI,KAAK,IAAI,EAC5C,gBAAgB,MAAM,EACtB,kBAAkB,MAAM,GAAG,IAAI,EAC/B,iBAAiB,kBAAkB,EACnC,qBAAqB,MAAM,OAAO,KACjC,IA6BF,CAAC"}
1
+ {"version":3,"file":"URLUtils.d.ts","sourceRoot":"","sources":["../../src/util/URLUtils.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;GAcG;AAGH,OAAO,KAAK,EAAE,kBAAkB,EAAE,MAAM,cAAc,CAAC;AAwDvD;;;;;;;;;;;;;;;;GAgBG;AACH,eAAO,MAAM,0BAA0B,GACrC,UAAU,MAAM,GAAG,OAAO,GAAG,MAAM,GAAG,IAAI,GAAG,SAAS,EACtD,gBAAgB,CAAC,GAAG,EAAE,MAAM,GAAG,IAAI,KAAK,IAAI,EAC5C,gBAAgB,MAAM,EACtB,kBAAkB,MAAM,GAAG,IAAI,EAC/B,iBAAiB,kBAAkB,EACnC,qBAAqB,MAAM,OAAO,EAClC,sBAAqB,OAAc,KAClC,IAwCF,CAAC"}
@@ -13,9 +13,61 @@
13
13
  * See the License for the specific language governing permissions and
14
14
  * limitations under the License.
15
15
  */
16
- import { useEffect } from 'react';
16
+ import { useEffect, useRef } from 'react';
17
+ /**
18
+ * Module-level queue for pending search param updates.
19
+ * This ensures all instances of the hook share the same queue,
20
+ * allowing updates to be batched together and applied in a single
21
+ * setSearchParams call.
22
+ *
23
+ * This is necessary because react-router's setSearchParams does not
24
+ * support queueing like React's setState does. Multiple calls to
25
+ * setSearchParams in the same tick will not build on the prior value.
26
+ * See: https://github.com/remix-run/react-router/issues/9304
27
+ */
28
+ const pendingUpdates = new Map();
29
+ let flushScheduled = false;
30
+ let currentSetSearchParams = null;
31
+ const flushUpdates = () => {
32
+ if (pendingUpdates.size === 0 || !currentSetSearchParams) {
33
+ flushScheduled = false;
34
+ return;
35
+ }
36
+ const setSearchParams = currentSetSearchParams;
37
+ const updates = new Map(pendingUpdates);
38
+ pendingUpdates.clear();
39
+ flushScheduled = false;
40
+ setSearchParams((params) => {
41
+ const newParams = new URLSearchParams(params);
42
+ updates.forEach((value, key) => {
43
+ if (value !== null) {
44
+ newParams.set(key, value);
45
+ }
46
+ else {
47
+ newParams.delete(key);
48
+ }
49
+ });
50
+ return newParams;
51
+ });
52
+ };
53
+ const queueUpdate = (key, value, setSearchParams) => {
54
+ pendingUpdates.set(key, value);
55
+ currentSetSearchParams = setSearchParams;
56
+ if (!flushScheduled) {
57
+ flushScheduled = true;
58
+ // Use queueMicrotask to batch updates in the same tick
59
+ queueMicrotask(flushUpdates);
60
+ }
61
+ };
17
62
  /**
18
63
  * Util hook to keep a state variable in sync with a URL search parameter.
64
+ * This hook syncs from URL to state if the state is null/undefined (so
65
+ * initial value is set from URL) and from state to URL otherwise.
66
+ *
67
+ * This hook properly queues setSearchParams calls to ensure all updates
68
+ * are applied, working around react-router's limitation where multiple
69
+ * calls to setSearchParams in the same tick don't build on each other.
70
+ * See: https://github.com/remix-run/react-router/issues/9304
19
71
  *
20
72
  * @param stateVar the state variable to sync
21
73
  * @param updateStateVar setter function to update the state variable (should be memoized with useCallback)
@@ -24,34 +76,37 @@ import { useEffect } from 'react';
24
76
  * @param setSearchParams function to update the URL search parameters (i.e., from useSearchParams)
25
77
  * @param initializedCallback function to check if the underlying state is initialized and ready to sync with URL (should be memoized with useCallback)
26
78
  */
27
- export const useSyncStateAndSearchParam = (stateVar, updateStateVar, searchParamKey, searchParamValue, setSearchParams, initializedCallback) => {
28
- // Sync state with URL search param
79
+ export const useSyncStateAndSearchParam = (stateVar, updateStateVar, searchParamKey, searchParamValue, setSearchParams, initializedCallback, clearParamOnUnmount = true) => {
80
+ // Use a ref to make setSearchParams stable
81
+ // react-router's setSearchParams is not stable and changes on every render
82
+ // See: https://github.com/remix-run/react-router/issues/9304
83
+ const setSearchParamsRef = useRef(setSearchParams);
84
+ setSearchParamsRef.current = setSearchParams;
85
+ // Sync state with URL search param if state is null/undefined
29
86
  useEffect(() => {
30
- if (initializedCallback()) {
31
- // On mount or when search param value changes, update state from URL
32
- const urlParamValue = searchParamValue;
33
- updateStateVar(urlParamValue);
87
+ if (initializedCallback() &&
88
+ (stateVar === null || stateVar === undefined)) {
89
+ updateStateVar(searchParamValue);
34
90
  }
35
- }, [initializedCallback, searchParamKey, searchParamValue, updateStateVar]);
91
+ }, [initializedCallback, searchParamValue, stateVar, updateStateVar]);
36
92
  // Sync URL search param with state
37
93
  useEffect(() => {
38
94
  if (initializedCallback()) {
39
- // When state changes, update URL param
40
- if (stateVar) {
41
- setSearchParams((params) => {
42
- const newParams = new URLSearchParams(params);
43
- newParams.set(searchParamKey, String(stateVar));
44
- return newParams;
45
- });
95
+ // When state changes, queue URL param update
96
+ // Using the queueing mechanism ensures all updates are applied
97
+ // even when multiple hooks call setSearchParams in the same tick
98
+ if (stateVar !== null && stateVar !== undefined) {
99
+ queueUpdate(searchParamKey, String(stateVar), setSearchParamsRef.current);
46
100
  }
47
101
  else {
48
- setSearchParams((params) => {
49
- const newParams = new URLSearchParams(params);
50
- newParams.delete(searchParamKey);
51
- return newParams;
52
- });
102
+ queueUpdate(searchParamKey, null, setSearchParamsRef.current);
53
103
  }
54
104
  }
55
- }, [initializedCallback, searchParamKey, stateVar, setSearchParams]);
105
+ return () => {
106
+ if (clearParamOnUnmount) {
107
+ queueUpdate(searchParamKey, null, setSearchParamsRef.current);
108
+ }
109
+ };
110
+ }, [clearParamOnUnmount, initializedCallback, searchParamKey, stateVar]);
56
111
  };
57
112
  //# sourceMappingURL=URLUtils.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"URLUtils.js","sourceRoot":"","sources":["../../src/util/URLUtils.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;GAcG;AAEH,OAAO,EAAE,SAAS,EAAE,MAAM,OAAO,CAAC;AAGlC;;;;;;;;;GASG;AACH,MAAM,CAAC,MAAM,0BAA0B,GAAG,CACxC,QAAsD,EACtD,cAA4C,EAC5C,cAAsB,EACtB,gBAA+B,EAC/B,eAAmC,EACnC,mBAAkC,EAC5B,EAAE;IACR,mCAAmC;IACnC,SAAS,CAAC,GAAG,EAAE;QACb,IAAI,mBAAmB,EAAE,EAAE,CAAC;YAC1B,qEAAqE;YACrE,MAAM,aAAa,GAAG,gBAAgB,CAAC;YACvC,cAAc,CAAC,aAAa,CAAC,CAAC;QAChC,CAAC;IACH,CAAC,EAAE,CAAC,mBAAmB,EAAE,cAAc,EAAE,gBAAgB,EAAE,cAAc,CAAC,CAAC,CAAC;IAE5E,mCAAmC;IACnC,SAAS,CAAC,GAAG,EAAE;QACb,IAAI,mBAAmB,EAAE,EAAE,CAAC;YAC1B,uCAAuC;YACvC,IAAI,QAAQ,EAAE,CAAC;gBACb,eAAe,CAAC,CAAC,MAAM,EAAE,EAAE;oBACzB,MAAM,SAAS,GAAG,IAAI,eAAe,CAAC,MAAM,CAAC,CAAC;oBAC9C,SAAS,CAAC,GAAG,CAAC,cAAc,EAAE,MAAM,CAAC,QAAQ,CAAC,CAAC,CAAC;oBAChD,OAAO,SAAS,CAAC;gBACnB,CAAC,CAAC,CAAC;YACL,CAAC;iBAAM,CAAC;gBACN,eAAe,CAAC,CAAC,MAAM,EAAE,EAAE;oBACzB,MAAM,SAAS,GAAG,IAAI,eAAe,CAAC,MAAM,CAAC,CAAC;oBAC9C,SAAS,CAAC,MAAM,CAAC,cAAc,CAAC,CAAC;oBACjC,OAAO,SAAS,CAAC;gBACnB,CAAC,CAAC,CAAC;YACL,CAAC;QACH,CAAC;IACH,CAAC,EAAE,CAAC,mBAAmB,EAAE,cAAc,EAAE,QAAQ,EAAE,eAAe,CAAC,CAAC,CAAC;AACvE,CAAC,CAAC"}
1
+ {"version":3,"file":"URLUtils.js","sourceRoot":"","sources":["../../src/util/URLUtils.ts"],"names":[],"mappings":"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"}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@finos/legend-application",
3
- "version": "16.0.91",
3
+ "version": "16.0.93",
4
4
  "description": "Legend application core",
5
5
  "keywords": [
6
6
  "legend",
@@ -45,7 +45,7 @@
45
45
  "test:watch": "jest --watch"
46
46
  },
47
47
  "dependencies": {
48
- "@finos/legend-art": "7.1.140",
48
+ "@finos/legend-art": "7.1.141",
49
49
  "@finos/legend-shared": "11.0.22",
50
50
  "@finos/legend-storage": "3.0.141",
51
51
  "@types/react": "19.0.10",
@@ -67,7 +67,7 @@
67
67
  "xterm-addon-webgl": "0.16.0"
68
68
  },
69
69
  "devDependencies": {
70
- "@finos/legend-dev-utils": "2.2.5",
70
+ "@finos/legend-dev-utils": "2.2.6",
71
71
  "@jest/globals": "29.7.0",
72
72
  "@testing-library/dom": "10.4.0",
73
73
  "@testing-library/react": "16.2.0",
@@ -55,4 +55,4 @@ export const EXTERNAL_APPLICATION_NAVIGATION__generateRegistryLineageUrl = (
55
55
  dataProductName: string,
56
56
  accessPointName: string,
57
57
  ): string =>
58
- `${registryApplicationUrl}#/lineage/lakehouse/dataProduct/${dataProductName.toUpperCase()}/accessPoint/${accessPointName.toUpperCase()}`;
58
+ `${registryApplicationUrl}/#/lineage/lakehouse/dataProduct/${dataProductName.toUpperCase()}/accessPoint/${accessPointName.toUpperCase()}`;
@@ -14,11 +14,72 @@
14
14
  * limitations under the License.
15
15
  */
16
16
 
17
- import { useEffect } from 'react';
17
+ import { useEffect, useRef } from 'react';
18
18
  import type { SetURLSearchParams } from 'react-router';
19
19
 
20
+ /**
21
+ * Module-level queue for pending search param updates.
22
+ * This ensures all instances of the hook share the same queue,
23
+ * allowing updates to be batched together and applied in a single
24
+ * setSearchParams call.
25
+ *
26
+ * This is necessary because react-router's setSearchParams does not
27
+ * support queueing like React's setState does. Multiple calls to
28
+ * setSearchParams in the same tick will not build on the prior value.
29
+ * See: https://github.com/remix-run/react-router/issues/9304
30
+ */
31
+ const pendingUpdates: Map<string, string | null> = new Map();
32
+ let flushScheduled = false;
33
+ let currentSetSearchParams: SetURLSearchParams | null = null;
34
+
35
+ const flushUpdates = (): void => {
36
+ if (pendingUpdates.size === 0 || !currentSetSearchParams) {
37
+ flushScheduled = false;
38
+ return;
39
+ }
40
+
41
+ const setSearchParams = currentSetSearchParams;
42
+ const updates = new Map(pendingUpdates);
43
+ pendingUpdates.clear();
44
+ flushScheduled = false;
45
+
46
+ setSearchParams((params) => {
47
+ const newParams = new URLSearchParams(params);
48
+ updates.forEach((value, key) => {
49
+ if (value !== null) {
50
+ newParams.set(key, value);
51
+ } else {
52
+ newParams.delete(key);
53
+ }
54
+ });
55
+ return newParams;
56
+ });
57
+ };
58
+
59
+ const queueUpdate = (
60
+ key: string,
61
+ value: string | null,
62
+ setSearchParams: SetURLSearchParams,
63
+ ): void => {
64
+ pendingUpdates.set(key, value);
65
+ currentSetSearchParams = setSearchParams;
66
+
67
+ if (!flushScheduled) {
68
+ flushScheduled = true;
69
+ // Use queueMicrotask to batch updates in the same tick
70
+ queueMicrotask(flushUpdates);
71
+ }
72
+ };
73
+
20
74
  /**
21
75
  * Util hook to keep a state variable in sync with a URL search parameter.
76
+ * This hook syncs from URL to state if the state is null/undefined (so
77
+ * initial value is set from URL) and from state to URL otherwise.
78
+ *
79
+ * This hook properly queues setSearchParams calls to ensure all updates
80
+ * are applied, working around react-router's limitation where multiple
81
+ * calls to setSearchParams in the same tick don't build on each other.
82
+ * See: https://github.com/remix-run/react-router/issues/9304
22
83
  *
23
84
  * @param stateVar the state variable to sync
24
85
  * @param updateStateVar setter function to update the state variable (should be memoized with useCallback)
@@ -34,33 +95,45 @@ export const useSyncStateAndSearchParam = (
34
95
  searchParamValue: string | null,
35
96
  setSearchParams: SetURLSearchParams,
36
97
  initializedCallback: () => boolean,
98
+ clearParamOnUnmount: boolean = true,
37
99
  ): void => {
38
- // Sync state with URL search param
100
+ // Use a ref to make setSearchParams stable
101
+ // react-router's setSearchParams is not stable and changes on every render
102
+ // See: https://github.com/remix-run/react-router/issues/9304
103
+ const setSearchParamsRef = useRef(setSearchParams);
104
+ setSearchParamsRef.current = setSearchParams;
105
+
106
+ // Sync state with URL search param if state is null/undefined
39
107
  useEffect(() => {
40
- if (initializedCallback()) {
41
- // On mount or when search param value changes, update state from URL
42
- const urlParamValue = searchParamValue;
43
- updateStateVar(urlParamValue);
108
+ if (
109
+ initializedCallback() &&
110
+ (stateVar === null || stateVar === undefined)
111
+ ) {
112
+ updateStateVar(searchParamValue);
44
113
  }
45
- }, [initializedCallback, searchParamKey, searchParamValue, updateStateVar]);
114
+ }, [initializedCallback, searchParamValue, stateVar, updateStateVar]);
46
115
 
47
116
  // Sync URL search param with state
48
117
  useEffect(() => {
49
118
  if (initializedCallback()) {
50
- // When state changes, update URL param
51
- if (stateVar) {
52
- setSearchParams((params) => {
53
- const newParams = new URLSearchParams(params);
54
- newParams.set(searchParamKey, String(stateVar));
55
- return newParams;
56
- });
119
+ // When state changes, queue URL param update
120
+ // Using the queueing mechanism ensures all updates are applied
121
+ // even when multiple hooks call setSearchParams in the same tick
122
+ if (stateVar !== null && stateVar !== undefined) {
123
+ queueUpdate(
124
+ searchParamKey,
125
+ String(stateVar),
126
+ setSearchParamsRef.current,
127
+ );
57
128
  } else {
58
- setSearchParams((params) => {
59
- const newParams = new URLSearchParams(params);
60
- newParams.delete(searchParamKey);
61
- return newParams;
62
- });
129
+ queueUpdate(searchParamKey, null, setSearchParamsRef.current);
63
130
  }
64
131
  }
65
- }, [initializedCallback, searchParamKey, stateVar, setSearchParams]);
132
+
133
+ return () => {
134
+ if (clearParamOnUnmount) {
135
+ queueUpdate(searchParamKey, null, setSearchParamsRef.current);
136
+ }
137
+ };
138
+ }, [clearParamOnUnmount, initializedCallback, searchParamKey, stateVar]);
66
139
  };