Skip to content

Commit e5ac45a

Browse files
committed
feat: add new hook useQueryStringState
1 parent 0397d3e commit e5ac45a

File tree

1 file changed

+33
-11
lines changed

1 file changed

+33
-11
lines changed

src/brouther/brouther.tsx

Lines changed: 33 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,5 @@
11
import React, { createContext, Fragment, useCallback, useContext, useEffect, useMemo, useRef, useState } from "react";
2+
import { jsonToURLSearchParams } from "../form/form-data-api";
23
import { RouterNavigator } from "../router/router-navigator";
34
import type { BroutherFlags, ConfiguredRoute, Location, PathFormat } from "../types";
45
import { BrowserHistory } from "../types/history";
@@ -124,16 +125,16 @@ export const Brouther = <T extends Base>({ config, flags, ErrorElement, children
124125
return void request().then((response) =>
125126
setState((prev) => ({
126127
...prev,
128+
matches: result,
129+
loading: response.loading,
127130
error: result.error ?? null,
128131
loaderData: response.loaderData,
129-
loading: response.loading,
130-
matches: result,
131132
}))
132133
);
133134
}, [findMatches, state.location.search, state.location.state, config, filter, state.location.pathname]);
134135

135136
useEffect(() => {
136-
config.history.listen((changes) => setState((p) => ({ ...p, location: { ...changes.location } })));
137+
config.history.listen((changes) => setState((p) => ({ ...p, location: changes.location })));
137138
}, [config.history]);
138139

139140
const href = createHref(state.location.pathname, state.location.search, state.location.hash, config.basename);
@@ -145,21 +146,21 @@ export const Brouther = <T extends Base>({ config, flags, ErrorElement, children
145146
const setLoading = useCallback((loading: boolean) => setState((prev) => ({ ...prev, loading })), []);
146147

147148
const context = {
149+
href,
150+
flags,
151+
config,
148152
setState,
153+
setLoading,
149154
actions: state.actions,
150155
matches: state.matches,
151-
config,
152-
basename: config.basename,
153-
error: state.matches.error ?? state.error,
154-
href,
155-
loaderData: state.loaderData,
156156
loading: state.loading,
157157
location: state.location,
158+
basename: config.basename,
159+
paths: state.matches.params,
158160
navigation: config.navigation,
159-
flags,
160-
setLoading,
161+
loaderData: state.loaderData,
162+
error: state.matches.error ?? state.error,
161163
page: state.error !== null ? null : state.matches.page,
162-
paths: state.matches.params,
163164
};
164165

165166
return (
@@ -343,3 +344,24 @@ export const useBeforeUnload = (fn: (event: BeforeUnloadEvent) => void) => {
343344
export const usePageStats = () => useBrouther().page;
344345

345346
export const useFormActions = <R extends object>(): ActionState<R> => useBrouther().actions;
347+
348+
/*
349+
The query-string state controller.
350+
*/
351+
export const useQueryStringState = <T extends {} | string>(_?: T): [qs: T extends string ? QueryString.Parse<T> : T, set: (newQuery: T) => void] => {
352+
const { href, page, navigation, location } = useBrouther();
353+
const urlSearchParams = useUrlSearchParams();
354+
const qs = useMemo(
355+
() => (page === null ? ({} as any) : transformData(urlSearchParams, mapUrlToQueryStringRecord(page.originalPath, fromStringToValue))),
356+
[href, page, urlSearchParams]
357+
);
358+
const callback = useCallback(
359+
(query: T) => {
360+
const location = new URL(window.location.href);
361+
location.search = jsonToURLSearchParams(query).toString();
362+
navigation.push(location.href);
363+
},
364+
[navigation]
365+
);
366+
return [qs, callback];
367+
};

0 commit comments

Comments
 (0)