Skip to content

Commit e4a799e

Browse files
committed
add experimental useRouteState
1 parent 2a32c29 commit e4a799e

File tree

1 file changed

+32
-15
lines changed

1 file changed

+32
-15
lines changed

router/index.tsx

Lines changed: 32 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,7 @@ import React, {
44
useCallback,
55
useContext,
66
useEffect,
7+
useReducer,
78
useRef,
89
useState,
910
useSyncExternalStore,
@@ -83,6 +84,25 @@ export const useReloadEffect = (
8384
*/
8485
export const ReloadContext = createContext(async (): Promise<void> => {});
8586

87+
let routeState: Record<string, any> = {};
88+
89+
/**
90+
* Returns a stateful value which bounded to route, and a function to update it.
91+
* Note that the value won't be updated across components.
92+
* So you should use this only in top-most component
93+
* @experimental
94+
* @param key unique key
95+
* @param initial initial value
96+
* @returns value and setter
97+
*/
98+
export function useRouteState<T extends {}>(key: string, initial: T) {
99+
return useReducer((_old: T, newvalue: T) => {
100+
// @ts-ignore
101+
routeState[key] = newvalue;
102+
return newvalue;
103+
}, (routeState[key] ?? initial) as unknown as T);
104+
}
105+
86106
export const RouterHost = ({
87107
children,
88108
Shell,
@@ -147,14 +167,11 @@ export const RouterHost = ({
147167
};
148168

149169
const subscribeToLocationUpdates = (callback: () => void) => {
170+
const abort = new AbortController();
150171
for (const event of events) {
151-
addEventListener(event, callback);
172+
window.addEventListener(event, callback, { signal: abort.signal });
152173
}
153-
return () => {
154-
for (const event of events) {
155-
removeEventListener(event, callback);
156-
}
157-
};
174+
return () => abort.abort();
158175
};
159176

160177
export function useLocationProperty<S extends Location[keyof Location]>(
@@ -186,21 +203,21 @@ export const navigate = (to: string, { replace = false } = {}) =>
186203
const eventPopstate = "popstate";
187204
const eventPushState = "pushState";
188205
const eventReplaceState = "replaceState";
189-
const eventHashchange = "hashchange";
190-
const events = [
191-
eventPopstate,
192-
eventPushState,
193-
eventReplaceState,
194-
eventHashchange,
195-
];
206+
const events = [eventPopstate, eventPushState, eventReplaceState];
196207

197208
if (typeof history !== "undefined") {
209+
window.addEventListener("popstate", (e) => {
210+
routeState = e.state ?? {};
211+
});
198212
for (const type of [eventPushState, eventReplaceState] as const) {
199213
const original = history[type];
200214
history[type] = function (
201-
...args: Parameters<(typeof history)[typeof type]>
215+
_data: any,
216+
_unused: string,
217+
url?: string | URL | null | undefined
202218
) {
203-
const result = original.apply(this, args);
219+
const result = original.apply(this, [routeState, "", url]);
220+
routeState = {};
204221
const event = new Event(type);
205222
unstable_batchedUpdates(() => {
206223
dispatchEvent(event);

0 commit comments

Comments
 (0)