react-router-dom 6.17.0 → 6.18.0-pre.1

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.
package/CHANGELOG.md CHANGED
@@ -1,5 +1,34 @@
1
1
  # `react-router-dom`
2
2
 
3
+ ## 6.18.0-pre.1
4
+
5
+ ### Patch Changes
6
+
7
+ - Updated dependencies:
8
+ - `@remix-run/router@1.11.0-pre.1`
9
+ - `react-router@6.18.0-pre.1`
10
+
11
+ ## 6.18.0-pre.0
12
+
13
+ ### Minor Changes
14
+
15
+ - Add support for manual fetcher key specification via `useFetcher({ key: string })` so you can access the same fetcher instance from different components in your application without prop-drilling ([RFC](https://github.com/remix-run/remix/discussions/7698)) ([#10960](https://github.com/remix-run/react-router/pull/10960))
16
+
17
+ - Fetcher keys are now also exposed on the fetchers returned from `useFetchers` so that they can be looked up by `key`
18
+
19
+ - Add `navigate`/`fetcherKey` params/props to `useSumbit`/`Form` to support kicking off a fetcher submission under the hood with an optionally user-specified `key` ([#10960](https://github.com/remix-run/react-router/pull/10960))
20
+
21
+ - Invoking a fetcher in this way is ephemeral and stateless
22
+ - If you need to access the state of one of these fetchers, you will need to leverage `useFetcher({ key })` to look it up elsewhere
23
+
24
+ ### Patch Changes
25
+
26
+ - Adds a fetcher context to `RouterProvider` that holds completed fetcher data, in preparation for the upcoming future flag that will change the fetcher persistence/cleanup behavior ([#10961](https://github.com/remix-run/react-router/pull/10961))
27
+ - Fix the `future`prop on `BrowserRouter`, `HashRouter` and `MemoryRouter` so that it accepts a `Partial<FutureConfig>` instead of requiring all flags to be included. ([#10962](https://github.com/remix-run/react-router/pull/10962))
28
+ - Updated dependencies:
29
+ - `@remix-run/router@1.11.0-pre.0`
30
+ - `react-router@6.18.0-pre.0`
31
+
3
32
  ## 6.17.0
4
33
 
5
34
  ### Minor Changes
package/dist/dom.d.ts CHANGED
@@ -56,6 +56,14 @@ export interface SubmitOptions {
56
56
  * Defaults to "application/x-www-form-urlencoded".
57
57
  */
58
58
  encType?: FormEncType;
59
+ /**
60
+ * Indicate a specific fetcherKey to use when using navigate=false
61
+ */
62
+ fetcherKey?: string;
63
+ /**
64
+ * navigate=false will use a fetcher instead of a navigation
65
+ */
66
+ navigate?: boolean;
59
67
  /**
60
68
  * Set `true` to replace the current entry in the browser's history stack
61
69
  * instead of creating a new one (i.e. stay on "the same page"). Defaults
package/dist/index.d.ts CHANGED
@@ -36,6 +36,9 @@ type ViewTransitionContextObject = {
36
36
  };
37
37
  declare const ViewTransitionContext: React.Context<ViewTransitionContextObject>;
38
38
  export { ViewTransitionContext as UNSAFE_ViewTransitionContext };
39
+ type FetchersContextObject = Map<string, any>;
40
+ declare const FetchersContext: React.Context<FetchersContextObject>;
41
+ export { FetchersContext as UNSAFE_FetchersContext };
39
42
  interface ViewTransition {
40
43
  finished: Promise<void>;
41
44
  ready: Promise<void>;
@@ -49,7 +52,7 @@ export declare function RouterProvider({ fallbackElement, router, future, }: Rou
49
52
  export interface BrowserRouterProps {
50
53
  basename?: string;
51
54
  children?: React.ReactNode;
52
- future?: FutureConfig;
55
+ future?: Partial<FutureConfig>;
53
56
  window?: Window;
54
57
  }
55
58
  /**
@@ -59,7 +62,7 @@ export declare function BrowserRouter({ basename, children, future, window, }: B
59
62
  export interface HashRouterProps {
60
63
  basename?: string;
61
64
  children?: React.ReactNode;
62
- future?: FutureConfig;
65
+ future?: Partial<FutureConfig>;
63
66
  window?: Window;
64
67
  }
65
68
  /**
@@ -147,6 +150,14 @@ export interface FetcherFormProps extends React.FormHTMLAttributes<HTMLFormEleme
147
150
  onSubmit?: React.FormEventHandler<HTMLFormElement>;
148
151
  }
149
152
  export interface FormProps extends FetcherFormProps {
153
+ /**
154
+ * Indicate a specific fetcherKey to use when using navigate=false
155
+ */
156
+ fetcherKey?: string;
157
+ /**
158
+ * navigate=false will use a fetcher instead of a navigation
159
+ */
160
+ navigate?: boolean;
150
161
  /**
151
162
  * Forces a full document navigation instead of a fetch.
152
163
  */
@@ -238,9 +249,8 @@ export declare function useSubmit(): SubmitFunction;
238
249
  export declare function useFormAction(action?: string, { relative }?: {
239
250
  relative?: RelativeRoutingType;
240
251
  }): string;
241
- declare function createFetcherForm(fetcherKey: string, routeId: string): React.ForwardRefExoticComponent<FetcherFormProps & React.RefAttributes<HTMLFormElement>>;
242
252
  export type FetcherWithComponents<TData> = Fetcher<TData> & {
243
- Form: ReturnType<typeof createFetcherForm>;
253
+ Form: React.ForwardRefExoticComponent<FetcherFormProps & React.RefAttributes<HTMLFormElement>>;
244
254
  submit: FetcherSubmitFunction;
245
255
  load: (href: string) => void;
246
256
  };
@@ -248,12 +258,16 @@ export type FetcherWithComponents<TData> = Fetcher<TData> & {
248
258
  * Interacts with route loaders and actions without causing a navigation. Great
249
259
  * for any interaction that stays on the same page.
250
260
  */
251
- export declare function useFetcher<TData = any>(): FetcherWithComponents<TData>;
261
+ export declare function useFetcher<TData = any>({ key, }?: {
262
+ key?: string;
263
+ }): FetcherWithComponents<TData>;
252
264
  /**
253
265
  * Provides all fetchers currently on the page. Useful for layouts and parent
254
266
  * routes that need to provide pending/optimistic UI regarding the fetch.
255
267
  */
256
- export declare function useFetchers(): Fetcher[];
268
+ export declare function useFetchers(): (Fetcher & {
269
+ key: string;
270
+ })[];
257
271
  /**
258
272
  * When rendered inside a RouterProvider, will restore scroll positions on navigations
259
273
  */
package/dist/index.js CHANGED
@@ -1,5 +1,5 @@
1
1
  /**
2
- * React Router DOM v6.17.0
2
+ * React Router DOM v6.18.0-pre.1
3
3
  *
4
4
  * Copyright (c) Remix Software Inc.
5
5
  *
@@ -11,7 +11,7 @@
11
11
  import * as React from 'react';
12
12
  import { UNSAFE_mapRouteProperties, UNSAFE_DataRouterContext, UNSAFE_DataRouterStateContext, Router, UNSAFE_useRoutesImpl, UNSAFE_NavigationContext, useHref, useResolvedPath, useLocation, useNavigate, createPath, UNSAFE_useRouteId, UNSAFE_RouteContext, useMatches, useNavigation, unstable_useBlocker } from 'react-router';
13
13
  export { AbortedDeferredError, Await, MemoryRouter, Navigate, NavigationType, Outlet, Route, Router, Routes, UNSAFE_DataRouterContext, UNSAFE_DataRouterStateContext, UNSAFE_LocationContext, UNSAFE_NavigationContext, UNSAFE_RouteContext, UNSAFE_useRouteId, createMemoryRouter, createPath, createRoutesFromChildren, createRoutesFromElements, defer, generatePath, isRouteErrorResponse, json, matchPath, matchRoutes, parsePath, redirect, redirectDocument, renderMatches, resolvePath, unstable_useBlocker, useActionData, useAsyncError, useAsyncValue, useHref, useInRouterContext, useLoaderData, useLocation, useMatch, useMatches, useNavigate, useNavigation, useNavigationType, useOutlet, useOutletContext, useParams, useResolvedPath, useRevalidator, useRouteError, useRouteLoaderData, useRoutes } from 'react-router';
14
- import { stripBasename, UNSAFE_warning, createRouter, createBrowserHistory, createHashHistory, UNSAFE_ErrorResponseImpl, UNSAFE_invariant, joinPaths, matchPath } from '@remix-run/router';
14
+ import { stripBasename, UNSAFE_warning, createRouter, createBrowserHistory, createHashHistory, UNSAFE_ErrorResponseImpl, UNSAFE_invariant, joinPaths, IDLE_FETCHER, matchPath } from '@remix-run/router';
15
15
 
16
16
  function _extends() {
17
17
  _extends = Object.assign ? Object.assign.bind() : function (target) {
@@ -208,7 +208,7 @@ function getFormSubmissionInfo(target, basename) {
208
208
 
209
209
  const _excluded = ["onClick", "relative", "reloadDocument", "replace", "state", "target", "to", "preventScrollReset", "unstable_viewTransition"],
210
210
  _excluded2 = ["aria-current", "caseSensitive", "className", "end", "style", "to", "unstable_viewTransition", "children"],
211
- _excluded3 = ["reloadDocument", "replace", "state", "method", "action", "onSubmit", "submit", "relative", "preventScrollReset", "unstable_viewTransition"];
211
+ _excluded3 = ["fetcherKey", "navigate", "reloadDocument", "replace", "state", "method", "action", "onSubmit", "relative", "preventScrollReset", "unstable_viewTransition"];
212
212
  function createBrowserRouter(routes, opts) {
213
213
  return createRouter({
214
214
  basename: opts == null ? void 0 : opts.basename,
@@ -294,6 +294,10 @@ const ViewTransitionContext = /*#__PURE__*/React.createContext({
294
294
  if (process.env.NODE_ENV !== "production") {
295
295
  ViewTransitionContext.displayName = "ViewTransition";
296
296
  }
297
+ const FetchersContext = /*#__PURE__*/React.createContext(new Map());
298
+ if (process.env.NODE_ENV !== "production") {
299
+ FetchersContext.displayName = "Fetchers";
300
+ }
297
301
  //#endregion
298
302
  ////////////////////////////////////////////////////////////////////////////////
299
303
  //#region Components
@@ -364,6 +368,7 @@ function RouterProvider(_ref) {
364
368
  let [renderDfd, setRenderDfd] = React.useState();
365
369
  let [transition, setTransition] = React.useState();
366
370
  let [interruption, setInterruption] = React.useState();
371
+ let fetcherData = React.useRef(new Map());
367
372
  let {
368
373
  v7_startTransition
369
374
  } = future || {};
@@ -376,8 +381,15 @@ function RouterProvider(_ref) {
376
381
  }, [v7_startTransition]);
377
382
  let setState = React.useCallback((newState, _ref2) => {
378
383
  let {
384
+ deletedFetchers,
379
385
  unstable_viewTransitionOpts: viewTransitionOpts
380
386
  } = _ref2;
387
+ deletedFetchers.forEach(key => fetcherData.current.delete(key));
388
+ newState.fetchers.forEach((fetcher, key) => {
389
+ if (fetcher.data !== undefined) {
390
+ fetcherData.current.set(key, fetcher.data);
391
+ }
392
+ });
381
393
  if (!viewTransitionOpts || router.window == null || typeof router.window.document.startViewTransition !== "function") {
382
394
  // Mid-navigation state update, or startViewTransition isn't available
383
395
  optInStartTransition(() => setStateImpl(newState));
@@ -400,7 +412,7 @@ function RouterProvider(_ref) {
400
412
  nextLocation: viewTransitionOpts.nextLocation
401
413
  });
402
414
  }
403
- }, [optInStartTransition, transition, renderDfd, router.window]);
415
+ }, [router.window, transition, renderDfd, fetcherData, optInStartTransition]);
404
416
  // Need to use a layout effect here so we are subscribed early enough to
405
417
  // pick up on any render-driven redirects/navigations (useEffect/<Navigate>)
406
418
  React.useLayoutEffect(() => router.subscribe(setState), [router, setState]);
@@ -486,6 +498,8 @@ function RouterProvider(_ref) {
486
498
  value: dataRouterContext
487
499
  }, /*#__PURE__*/React.createElement(UNSAFE_DataRouterStateContext.Provider, {
488
500
  value: state
501
+ }, /*#__PURE__*/React.createElement(FetchersContext.Provider, {
502
+ value: fetcherData.current
489
503
  }, /*#__PURE__*/React.createElement(ViewTransitionContext.Provider, {
490
504
  value: vtContext
491
505
  }, /*#__PURE__*/React.createElement(Router, {
@@ -496,7 +510,7 @@ function RouterProvider(_ref) {
496
510
  }, state.initialized ? /*#__PURE__*/React.createElement(DataRoutes, {
497
511
  routes: router.routes,
498
512
  state: state
499
- }) : fallbackElement)))), null);
513
+ }) : fallbackElement))))), null);
500
514
  }
501
515
  function DataRoutes(_ref3) {
502
516
  let {
@@ -765,34 +779,26 @@ if (process.env.NODE_ENV !== "production") {
765
779
  * requests, allowing components to add nicer UX to the page as the form is
766
780
  * submitted and returns with data.
767
781
  */
768
- const Form = /*#__PURE__*/React.forwardRef((props, ref) => {
769
- let submit = useSubmit();
770
- return /*#__PURE__*/React.createElement(FormImpl, _extends({}, props, {
771
- submit: submit,
772
- ref: ref
773
- }));
774
- });
775
- if (process.env.NODE_ENV !== "production") {
776
- Form.displayName = "Form";
777
- }
778
- const FormImpl = /*#__PURE__*/React.forwardRef((_ref9, forwardedRef) => {
782
+ const Form = /*#__PURE__*/React.forwardRef((_ref9, forwardedRef) => {
779
783
  let {
784
+ fetcherKey,
785
+ navigate,
780
786
  reloadDocument,
781
787
  replace,
782
788
  state,
783
789
  method = defaultMethod,
784
790
  action,
785
791
  onSubmit,
786
- submit,
787
792
  relative,
788
793
  preventScrollReset,
789
794
  unstable_viewTransition
790
795
  } = _ref9,
791
796
  props = _objectWithoutPropertiesLoose(_ref9, _excluded3);
792
- let formMethod = method.toLowerCase() === "get" ? "get" : "post";
797
+ let submit = useSubmit();
793
798
  let formAction = useFormAction(action, {
794
799
  relative
795
800
  });
801
+ let formMethod = method.toLowerCase() === "get" ? "get" : "post";
796
802
  let submitHandler = event => {
797
803
  onSubmit && onSubmit(event);
798
804
  if (event.defaultPrevented) return;
@@ -800,7 +806,9 @@ const FormImpl = /*#__PURE__*/React.forwardRef((_ref9, forwardedRef) => {
800
806
  let submitter = event.nativeEvent.submitter;
801
807
  let submitMethod = (submitter == null ? void 0 : submitter.getAttribute("formmethod")) || method;
802
808
  submit(submitter || event.currentTarget, {
809
+ fetcherKey,
803
810
  method: submitMethod,
811
+ navigate,
804
812
  replace,
805
813
  state,
806
814
  relative,
@@ -816,7 +824,7 @@ const FormImpl = /*#__PURE__*/React.forwardRef((_ref9, forwardedRef) => {
816
824
  }, props));
817
825
  });
818
826
  if (process.env.NODE_ENV !== "production") {
819
- FormImpl.displayName = "FormImpl";
827
+ Form.displayName = "Form";
820
828
  }
821
829
  /**
822
830
  * This component will emulate the browser's scroll restoration on location
@@ -850,9 +858,11 @@ var DataRouterHook;
850
858
  })(DataRouterHook || (DataRouterHook = {}));
851
859
  var DataRouterStateHook;
852
860
  (function (DataRouterStateHook) {
861
+ DataRouterStateHook["UseFetcher"] = "useFetcher";
853
862
  DataRouterStateHook["UseFetchers"] = "useFetchers";
854
863
  DataRouterStateHook["UseScrollRestoration"] = "useScrollRestoration";
855
864
  })(DataRouterStateHook || (DataRouterStateHook = {}));
865
+ // Internal hooks
856
866
  function getDataRouterConsoleError(hookName) {
857
867
  return hookName + " must be used within a data router. See https://reactrouter.com/routers/picking-a-router.";
858
868
  }
@@ -866,6 +876,7 @@ function useDataRouterState(hookName) {
866
876
  !state ? process.env.NODE_ENV !== "production" ? UNSAFE_invariant(false, getDataRouterConsoleError(hookName)) : UNSAFE_invariant(false) : void 0;
867
877
  return state;
868
878
  }
879
+ // External hooks
869
880
  /**
870
881
  * Handles the click behavior for router `<Link>` components. This is useful if
871
882
  * you need to create custom `<Link>` components with the same click behavior we
@@ -928,6 +939,8 @@ function validateClientSideSubmission() {
928
939
  throw new Error("You are calling submit during the server render. " + "Try calling submit within a `useEffect` or callback instead.");
929
940
  }
930
941
  }
942
+ let fetcherId = 0;
943
+ let getUniqueFetcherId = () => "__" + String(++fetcherId) + "__";
931
944
  /**
932
945
  * Returns a function that may be used to programmatically submit a form (or
933
946
  * some arbitrary data) to the server.
@@ -952,50 +965,29 @@ function useSubmit() {
952
965
  formData,
953
966
  body
954
967
  } = getFormSubmissionInfo(target, basename);
955
- router.navigate(options.action || action, {
956
- preventScrollReset: options.preventScrollReset,
957
- formData,
958
- body,
959
- formMethod: options.method || method,
960
- formEncType: options.encType || encType,
961
- replace: options.replace,
962
- state: options.state,
963
- fromRouteId: currentRouteId,
964
- unstable_viewTransition: options.unstable_viewTransition
965
- });
966
- }, [router, basename, currentRouteId]);
967
- }
968
- /**
969
- * Returns the implementation for fetcher.submit
970
- */
971
- function useSubmitFetcher(fetcherKey, fetcherRouteId) {
972
- let {
973
- router
974
- } = useDataRouterContext(DataRouterHook.UseSubmitFetcher);
975
- let {
976
- basename
977
- } = React.useContext(UNSAFE_NavigationContext);
978
- return React.useCallback(function (target, options) {
979
- if (options === void 0) {
980
- options = {};
968
+ if (options.navigate === false) {
969
+ let key = options.fetcherKey || getUniqueFetcherId();
970
+ router.fetch(key, currentRouteId, options.action || action, {
971
+ preventScrollReset: options.preventScrollReset,
972
+ formData,
973
+ body,
974
+ formMethod: options.method || method,
975
+ formEncType: options.encType || encType
976
+ });
977
+ } else {
978
+ router.navigate(options.action || action, {
979
+ preventScrollReset: options.preventScrollReset,
980
+ formData,
981
+ body,
982
+ formMethod: options.method || method,
983
+ formEncType: options.encType || encType,
984
+ replace: options.replace,
985
+ state: options.state,
986
+ fromRouteId: currentRouteId,
987
+ unstable_viewTransition: options.unstable_viewTransition
988
+ });
981
989
  }
982
- validateClientSideSubmission();
983
- let {
984
- action,
985
- method,
986
- encType,
987
- formData,
988
- body
989
- } = getFormSubmissionInfo(target, basename);
990
- !(fetcherRouteId != null) ? process.env.NODE_ENV !== "production" ? UNSAFE_invariant(false, "No routeId available for useFetcher()") : UNSAFE_invariant(false) : void 0;
991
- router.fetch(fetcherKey, fetcherRouteId, options.action || action, {
992
- preventScrollReset: options.preventScrollReset,
993
- formData,
994
- body,
995
- formMethod: options.method || method,
996
- formEncType: options.encType || encType
997
- });
998
- }, [router, basename, fetcherKey, fetcherRouteId]);
990
+ }, [router, basename, currentRouteId]);
999
991
  }
1000
992
  // v7: Eventually we should deprecate this entirely in favor of using the
1001
993
  // router method directly?
@@ -1045,63 +1037,76 @@ function useFormAction(action, _temp2) {
1045
1037
  }
1046
1038
  return createPath(path);
1047
1039
  }
1048
- function createFetcherForm(fetcherKey, routeId) {
1049
- let FetcherForm = /*#__PURE__*/React.forwardRef((props, ref) => {
1050
- let submit = useSubmitFetcher(fetcherKey, routeId);
1051
- return /*#__PURE__*/React.createElement(FormImpl, _extends({}, props, {
1052
- ref: ref,
1053
- submit: submit
1054
- }));
1055
- });
1056
- if (process.env.NODE_ENV !== "production") {
1057
- FetcherForm.displayName = "fetcher.Form";
1058
- }
1059
- return FetcherForm;
1060
- }
1061
- let fetcherId = 0;
1062
1040
  // TODO: (v7) Change the useFetcher generic default from `any` to `unknown`
1063
1041
  /**
1064
1042
  * Interacts with route loaders and actions without causing a navigation. Great
1065
1043
  * for any interaction that stays on the same page.
1066
1044
  */
1067
- function useFetcher() {
1045
+ function useFetcher(_temp3) {
1068
1046
  var _route$matches;
1047
+ let {
1048
+ key
1049
+ } = _temp3 === void 0 ? {} : _temp3;
1069
1050
  let {
1070
1051
  router
1071
1052
  } = useDataRouterContext(DataRouterHook.UseFetcher);
1053
+ let state = useDataRouterState(DataRouterStateHook.UseFetcher);
1054
+ let fetcherData = React.useContext(FetchersContext);
1072
1055
  let route = React.useContext(UNSAFE_RouteContext);
1073
- !route ? process.env.NODE_ENV !== "production" ? UNSAFE_invariant(false, "useFetcher must be used inside a RouteContext") : UNSAFE_invariant(false) : void 0;
1074
1056
  let routeId = (_route$matches = route.matches[route.matches.length - 1]) == null ? void 0 : _route$matches.route.id;
1057
+ !fetcherData ? process.env.NODE_ENV !== "production" ? UNSAFE_invariant(false, "useFetcher must be used inside a FetchersContext") : UNSAFE_invariant(false) : void 0;
1058
+ !route ? process.env.NODE_ENV !== "production" ? UNSAFE_invariant(false, "useFetcher must be used inside a RouteContext") : UNSAFE_invariant(false) : void 0;
1075
1059
  !(routeId != null) ? process.env.NODE_ENV !== "production" ? UNSAFE_invariant(false, "useFetcher can only be used on routes that contain a unique \"id\"") : UNSAFE_invariant(false) : void 0;
1076
- let [fetcherKey] = React.useState(() => String(++fetcherId));
1077
- let [Form] = React.useState(() => {
1078
- !routeId ? process.env.NODE_ENV !== "production" ? UNSAFE_invariant(false, "No routeId available for fetcher.Form()") : UNSAFE_invariant(false) : void 0;
1079
- return createFetcherForm(fetcherKey, routeId);
1080
- });
1081
- let [load] = React.useState(() => href => {
1082
- !router ? process.env.NODE_ENV !== "production" ? UNSAFE_invariant(false, "No router available for fetcher.load()") : UNSAFE_invariant(false) : void 0;
1083
- !routeId ? process.env.NODE_ENV !== "production" ? UNSAFE_invariant(false, "No routeId available for fetcher.load()") : UNSAFE_invariant(false) : void 0;
1084
- router.fetch(fetcherKey, routeId, href);
1085
- });
1086
- let submit = useSubmitFetcher(fetcherKey, routeId);
1087
- let fetcher = router.getFetcher(fetcherKey);
1088
- let fetcherWithComponents = React.useMemo(() => _extends({
1089
- Form,
1090
- submit,
1091
- load
1092
- }, fetcher), [fetcher, Form, submit, load]);
1060
+ // Fetcher key handling
1061
+ let [fetcherKey, setFetcherKey] = React.useState(key || "");
1062
+ if (!fetcherKey) {
1063
+ setFetcherKey(getUniqueFetcherId());
1064
+ }
1065
+ // Registration/cleanup
1093
1066
  React.useEffect(() => {
1094
- // Is this busted when the React team gets real weird and calls effects
1095
- // twice on mount? We really just need to garbage collect here when this
1096
- // fetcher is no longer around.
1067
+ router.getFetcher(fetcherKey);
1097
1068
  return () => {
1098
- if (!router) {
1099
- console.warn("No router available to clean up from useFetcher()");
1100
- return;
1101
- }
1069
+ // Tell the router we've unmounted - if v7_fetcherPersist is enabled this
1070
+ // will not delete immediately but instead queue up a delete after the
1071
+ // fetcher returns to an `idle` state
1102
1072
  router.deleteFetcher(fetcherKey);
1103
1073
  };
1104
1074
  }, [router, fetcherKey]);
1075
+ // Fetcher additions
1076
+ let load = React.useCallback(href => {
1077
+ !routeId ? process.env.NODE_ENV !== "production" ? UNSAFE_invariant(false, "No routeId available for fetcher.load()") : UNSAFE_invariant(false) : void 0;
1078
+ router.fetch(fetcherKey, routeId, href);
1079
+ }, [fetcherKey, routeId, router]);
1080
+ let submitImpl = useSubmit();
1081
+ let submit = React.useCallback((target, opts) => {
1082
+ submitImpl(target, _extends({}, opts, {
1083
+ navigate: false,
1084
+ fetcherKey
1085
+ }));
1086
+ }, [fetcherKey, submitImpl]);
1087
+ let FetcherForm = React.useMemo(() => {
1088
+ let FetcherForm = /*#__PURE__*/React.forwardRef((props, ref) => {
1089
+ return /*#__PURE__*/React.createElement(Form, _extends({}, props, {
1090
+ navigate: false,
1091
+ fetcherKey: fetcherKey,
1092
+ ref: ref
1093
+ }));
1094
+ });
1095
+ if (process.env.NODE_ENV !== "production") {
1096
+ FetcherForm.displayName = "fetcher.Form";
1097
+ }
1098
+ return FetcherForm;
1099
+ }, [fetcherKey]);
1100
+ // Exposed FetcherWithComponents
1101
+ let fetcher = state.fetchers.get(fetcherKey) || IDLE_FETCHER;
1102
+ let data = fetcherData.get(fetcherKey);
1103
+ let fetcherWithComponents = React.useMemo(() => _extends({
1104
+ Form: FetcherForm,
1105
+ submit,
1106
+ load
1107
+ }, fetcher, {
1108
+ data
1109
+ }), [FetcherForm, submit, load, fetcher, data]);
1105
1110
  return fetcherWithComponents;
1106
1111
  }
1107
1112
  /**
@@ -1110,18 +1115,23 @@ function useFetcher() {
1110
1115
  */
1111
1116
  function useFetchers() {
1112
1117
  let state = useDataRouterState(DataRouterStateHook.UseFetchers);
1113
- return [...state.fetchers.values()];
1118
+ return Array.from(state.fetchers.entries()).map(_ref11 => {
1119
+ let [key, fetcher] = _ref11;
1120
+ return _extends({}, fetcher, {
1121
+ key
1122
+ });
1123
+ });
1114
1124
  }
1115
1125
  const SCROLL_RESTORATION_STORAGE_KEY = "react-router-scroll-positions";
1116
1126
  let savedScrollPositions = {};
1117
1127
  /**
1118
1128
  * When rendered inside a RouterProvider, will restore scroll positions on navigations
1119
1129
  */
1120
- function useScrollRestoration(_temp3) {
1130
+ function useScrollRestoration(_temp4) {
1121
1131
  let {
1122
1132
  getKey,
1123
1133
  storageKey
1124
- } = _temp3 === void 0 ? {} : _temp3;
1134
+ } = _temp4 === void 0 ? {} : _temp4;
1125
1135
  let {
1126
1136
  router
1127
1137
  } = useDataRouterContext(DataRouterHook.UseScrollRestoration);
@@ -1259,11 +1269,11 @@ function usePageHide(callback, options) {
1259
1269
  * very incorrectly in some cases) across browsers if user click addition
1260
1270
  * back/forward navigations while the confirm is open. Use at your own risk.
1261
1271
  */
1262
- function usePrompt(_ref11) {
1272
+ function usePrompt(_ref12) {
1263
1273
  let {
1264
1274
  when,
1265
1275
  message
1266
- } = _ref11;
1276
+ } = _ref12;
1267
1277
  let blocker = unstable_useBlocker(when);
1268
1278
  React.useEffect(() => {
1269
1279
  if (blocker.state === "blocked") {
@@ -1326,5 +1336,5 @@ function useViewTransitionState(to, opts) {
1326
1336
  }
1327
1337
  //#endregion
1328
1338
 
1329
- export { BrowserRouter, Form, HashRouter, Link, NavLink, RouterProvider, ScrollRestoration, ViewTransitionContext as UNSAFE_ViewTransitionContext, useScrollRestoration as UNSAFE_useScrollRestoration, createBrowserRouter, createHashRouter, createSearchParams, HistoryRouter as unstable_HistoryRouter, usePrompt as unstable_usePrompt, useViewTransitionState as unstable_useViewTransitionState, useBeforeUnload, useFetcher, useFetchers, useFormAction, useLinkClickHandler, useSearchParams, useSubmit };
1339
+ export { BrowserRouter, Form, HashRouter, Link, NavLink, RouterProvider, ScrollRestoration, FetchersContext as UNSAFE_FetchersContext, ViewTransitionContext as UNSAFE_ViewTransitionContext, useScrollRestoration as UNSAFE_useScrollRestoration, createBrowserRouter, createHashRouter, createSearchParams, HistoryRouter as unstable_HistoryRouter, usePrompt as unstable_usePrompt, useViewTransitionState as unstable_useViewTransitionState, useBeforeUnload, useFetcher, useFetchers, useFormAction, useLinkClickHandler, useSearchParams, useSubmit };
1330
1340
  //# sourceMappingURL=index.js.map