react-router-dom 0.0.0-experimental-1e8b7a59 → 0.0.0-experimental-e0f088aa

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/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,13 @@ type ViewTransitionContextObject = {
36
36
  };
37
37
  declare const ViewTransitionContext: React.Context<ViewTransitionContextObject>;
38
38
  export { ViewTransitionContext as UNSAFE_ViewTransitionContext };
39
+ type FetchersContextObject = {
40
+ data: Map<string, any>;
41
+ register: (key: string) => void;
42
+ unregister: (key: string) => void;
43
+ };
44
+ declare const FetchersContext: React.Context<FetchersContextObject | null>;
45
+ export { FetchersContext as UNSAFE_FetchersContext };
39
46
  interface ViewTransition {
40
47
  finished: Promise<void>;
41
48
  ready: Promise<void>;
@@ -147,6 +154,14 @@ export interface FetcherFormProps extends React.FormHTMLAttributes<HTMLFormEleme
147
154
  onSubmit?: React.FormEventHandler<HTMLFormElement>;
148
155
  }
149
156
  export interface FormProps extends FetcherFormProps {
157
+ /**
158
+ * Indicate a specific fetcherKey to use when using navigate=false
159
+ */
160
+ fetcherKey?: string;
161
+ /**
162
+ * navigate=false will use a fetcher instead of a navigation
163
+ */
164
+ navigate?: boolean;
150
165
  /**
151
166
  * Forces a full document navigation instead of a fetch.
152
167
  */
@@ -238,9 +253,8 @@ export declare function useSubmit(): SubmitFunction;
238
253
  export declare function useFormAction(action?: string, { relative }?: {
239
254
  relative?: RelativeRoutingType;
240
255
  }): string;
241
- declare function createFetcherForm(fetcherKey: string, routeId: string, persist: boolean): React.ForwardRefExoticComponent<FetcherFormProps & React.RefAttributes<HTMLFormElement>>;
242
256
  export type FetcherWithComponents<TData> = Fetcher<TData> & {
243
- Form: ReturnType<typeof createFetcherForm>;
257
+ Form: React.ForwardRefExoticComponent<FetcherFormProps & React.RefAttributes<HTMLFormElement>>;
244
258
  submit: FetcherSubmitFunction;
245
259
  load: (href: string) => void;
246
260
  };
@@ -248,9 +262,8 @@ export type FetcherWithComponents<TData> = Fetcher<TData> & {
248
262
  * Interacts with route loaders and actions without causing a navigation. Great
249
263
  * for any interaction that stays on the same page.
250
264
  */
251
- export declare function useFetcher<TData = any>({ key, persist, }?: {
265
+ export declare function useFetcher<TData = any>({ key, }?: {
252
266
  key?: string;
253
- persist?: boolean;
254
267
  }): FetcherWithComponents<TData>;
255
268
  /**
256
269
  * Provides all fetchers currently on the page. Useful for layouts and parent
package/dist/index.js CHANGED
@@ -1,5 +1,5 @@
1
1
  /**
2
- * React Router DOM v0.0.0-experimental-1e8b7a59
2
+ * React Router DOM v0.0.0-experimental-e0f088aa
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", "submit", "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(null);
298
+ if (process.env.NODE_ENV !== "production") {
299
+ FetchersContext.displayName = "Fetchers";
300
+ }
297
301
  //#endregion
298
302
  ////////////////////////////////////////////////////////////////////////////////
299
303
  //#region Components
@@ -364,6 +368,32 @@ 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 fetcherRefs = React.useRef(new Map());
372
+ let fetcherData = React.useRef(new Map());
373
+ let registerFetcher = React.useCallback(key => {
374
+ let count = fetcherRefs.current.get(key);
375
+ if (count == null) {
376
+ fetcherRefs.current.set(key, 1);
377
+ } else {
378
+ fetcherRefs.current.set(key, count + 1);
379
+ }
380
+ }, []);
381
+ let unregisterFetcher = React.useCallback(key => {
382
+ let count = fetcherRefs.current.get(key);
383
+ if (count == null || count <= 1) {
384
+ fetcherRefs.current.delete(key);
385
+ fetcherData.current.delete(key);
386
+ } else {
387
+ fetcherRefs.current.set(key, count - 1);
388
+ }
389
+ }, [fetcherData]);
390
+ let fetcherContext = React.useMemo(() => ({
391
+ data: fetcherData.current,
392
+ register: registerFetcher,
393
+ unregister: unregisterFetcher
394
+ }), [registerFetcher, unregisterFetcher]);
395
+ // console.log("fetcherRefs", fetcherRefs.current);
396
+ // console.log("fetcherData", fetcherData.current);
367
397
  let {
368
398
  v7_startTransition
369
399
  } = future || {};
@@ -378,6 +408,11 @@ function RouterProvider(_ref) {
378
408
  let {
379
409
  unstable_viewTransitionOpts: viewTransitionOpts
380
410
  } = _ref2;
411
+ newState.fetchers.forEach((fetcher, key) => {
412
+ if (fetcher.data !== undefined) {
413
+ fetcherData.current.set(key, fetcher.data);
414
+ }
415
+ });
381
416
  if (!viewTransitionOpts || router.window == null || typeof router.window.document.startViewTransition !== "function") {
382
417
  // Mid-navigation state update, or startViewTransition isn't available
383
418
  optInStartTransition(() => setStateImpl(newState));
@@ -486,6 +521,8 @@ function RouterProvider(_ref) {
486
521
  value: dataRouterContext
487
522
  }, /*#__PURE__*/React.createElement(UNSAFE_DataRouterStateContext.Provider, {
488
523
  value: state
524
+ }, /*#__PURE__*/React.createElement(FetchersContext.Provider, {
525
+ value: fetcherContext
489
526
  }, /*#__PURE__*/React.createElement(ViewTransitionContext.Provider, {
490
527
  value: vtContext
491
528
  }, /*#__PURE__*/React.createElement(Router, {
@@ -496,7 +533,7 @@ function RouterProvider(_ref) {
496
533
  }, state.initialized ? /*#__PURE__*/React.createElement(DataRoutes, {
497
534
  routes: router.routes,
498
535
  state: state
499
- }) : fallbackElement)))), null);
536
+ }) : fallbackElement))))), null);
500
537
  }
501
538
  function DataRoutes(_ref3) {
502
539
  let {
@@ -777,6 +814,8 @@ if (process.env.NODE_ENV !== "production") {
777
814
  }
778
815
  const FormImpl = /*#__PURE__*/React.forwardRef((_ref9, forwardedRef) => {
779
816
  let {
817
+ fetcherKey,
818
+ navigate,
780
819
  reloadDocument,
781
820
  replace,
782
821
  state,
@@ -800,7 +839,9 @@ const FormImpl = /*#__PURE__*/React.forwardRef((_ref9, forwardedRef) => {
800
839
  let submitter = event.nativeEvent.submitter;
801
840
  let submitMethod = (submitter == null ? void 0 : submitter.getAttribute("formmethod")) || method;
802
841
  submit(submitter || event.currentTarget, {
842
+ fetcherKey,
803
843
  method: submitMethod,
844
+ navigate,
804
845
  replace,
805
846
  state,
806
847
  relative,
@@ -850,6 +891,7 @@ var DataRouterHook;
850
891
  })(DataRouterHook || (DataRouterHook = {}));
851
892
  var DataRouterStateHook;
852
893
  (function (DataRouterStateHook) {
894
+ DataRouterStateHook["UseFetcher"] = "useFetcher";
853
895
  DataRouterStateHook["UseFetchers"] = "useFetchers";
854
896
  DataRouterStateHook["UseScrollRestoration"] = "useScrollRestoration";
855
897
  })(DataRouterStateHook || (DataRouterStateHook = {}));
@@ -928,6 +970,8 @@ function validateClientSideSubmission() {
928
970
  throw new Error("You are calling submit during the server render. " + "Try calling submit within a `useEffect` or callback instead.");
929
971
  }
930
972
  }
973
+ let fetcherId = 0;
974
+ let getUniqueFetcherId = () => "__" + String(++fetcherId) + "__";
931
975
  /**
932
976
  * Returns a function that may be used to programmatically submit a form (or
933
977
  * some arbitrary data) to the server.
@@ -952,51 +996,29 @@ function useSubmit() {
952
996
  formData,
953
997
  body
954
998
  } = 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, persist) {
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 = {};
999
+ if (options.navigate === false) {
1000
+ let key = options.fetcherKey || getUniqueFetcherId();
1001
+ router.fetch(key, currentRouteId, options.action || action, {
1002
+ preventScrollReset: options.preventScrollReset,
1003
+ formData,
1004
+ body,
1005
+ formMethod: options.method || method,
1006
+ formEncType: options.encType || encType
1007
+ });
1008
+ } else {
1009
+ router.navigate(options.action || action, {
1010
+ preventScrollReset: options.preventScrollReset,
1011
+ formData,
1012
+ body,
1013
+ formMethod: options.method || method,
1014
+ formEncType: options.encType || encType,
1015
+ replace: options.replace,
1016
+ state: options.state,
1017
+ fromRouteId: currentRouteId,
1018
+ unstable_viewTransition: options.unstable_viewTransition
1019
+ });
981
1020
  }
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
- persist
998
- });
999
- }, [router, basename, fetcherKey, fetcherRouteId, persist]);
1021
+ }, [router, basename, currentRouteId]);
1000
1022
  }
1001
1023
  // v7: Eventually we should deprecate this entirely in favor of using the
1002
1024
  // router method directly?
@@ -1044,20 +1066,6 @@ function useFormAction(action, _temp2) {
1044
1066
  }
1045
1067
  return createPath(path);
1046
1068
  }
1047
- function createFetcherForm(fetcherKey, routeId, persist) {
1048
- let FetcherForm = /*#__PURE__*/React.forwardRef((props, ref) => {
1049
- let submit = useSubmitFetcher(fetcherKey, routeId, persist);
1050
- return /*#__PURE__*/React.createElement(FormImpl, _extends({}, props, {
1051
- ref: ref,
1052
- submit: submit
1053
- }));
1054
- });
1055
- if (process.env.NODE_ENV !== "production") {
1056
- FetcherForm.displayName = "fetcher.Form";
1057
- }
1058
- return FetcherForm;
1059
- }
1060
- let fetcherId = 0;
1061
1069
  // TODO: (v7) Change the useFetcher generic default from `any` to `unknown`
1062
1070
  /**
1063
1071
  * Interacts with route loaders and actions without causing a navigation. Great
@@ -1066,47 +1074,70 @@ let fetcherId = 0;
1066
1074
  function useFetcher(_temp3) {
1067
1075
  var _route$matches;
1068
1076
  let {
1069
- key,
1070
- persist
1077
+ key
1071
1078
  } = _temp3 === void 0 ? {} : _temp3;
1072
1079
  let {
1073
1080
  router
1074
1081
  } = useDataRouterContext(DataRouterHook.UseFetcher);
1082
+ let state = useDataRouterState(DataRouterStateHook.UseFetcher);
1083
+ let fetchersCtx = React.useContext(FetchersContext);
1075
1084
  let route = React.useContext(UNSAFE_RouteContext);
1076
- !route ? process.env.NODE_ENV !== "production" ? UNSAFE_invariant(false, "useFetcher must be used inside a RouteContext") : UNSAFE_invariant(false) : void 0;
1077
1085
  let routeId = (_route$matches = route.matches[route.matches.length - 1]) == null ? void 0 : _route$matches.route.id;
1086
+ let [fetcherKey, setFetcherKey] = React.useState(key || "");
1087
+ if (!fetcherKey) {
1088
+ setFetcherKey(getUniqueFetcherId());
1089
+ }
1090
+ !fetchersCtx ? process.env.NODE_ENV !== "production" ? UNSAFE_invariant(false, "useFetcher must be used inside a FetchersContext") : UNSAFE_invariant(false) : void 0;
1091
+ !route ? process.env.NODE_ENV !== "production" ? UNSAFE_invariant(false, "useFetcher must be used inside a RouteContext") : UNSAFE_invariant(false) : void 0;
1078
1092
  !(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;
1079
- let [_fetcherKey] = React.useState(() => "__" + String(++fetcherId));
1080
- let fetcherKey = key ? key : _fetcherKey;
1081
- let [Form] = React.useState(() => {
1082
- !routeId ? process.env.NODE_ENV !== "production" ? UNSAFE_invariant(false, "No routeId available for fetcher.Form()") : UNSAFE_invariant(false) : void 0;
1083
- return createFetcherForm(fetcherKey, routeId, persist === true);
1084
- });
1085
- let [load] = React.useState(() => href => {
1086
- !router ? process.env.NODE_ENV !== "production" ? UNSAFE_invariant(false, "No router available for fetcher.load()") : UNSAFE_invariant(false) : void 0;
1087
- !routeId ? process.env.NODE_ENV !== "production" ? UNSAFE_invariant(false, "No routeId available for fetcher.load()") : UNSAFE_invariant(false) : void 0;
1088
- router.fetch(fetcherKey, routeId, href);
1089
- });
1090
- let submit = useSubmitFetcher(fetcherKey, routeId, persist === true);
1091
- let fetcher = router.getFetcher(fetcherKey);
1092
- let fetcherWithComponents = React.useMemo(() => _extends({
1093
- Form,
1094
- submit,
1095
- load
1096
- }, fetcher), [fetcher, Form, submit, load]);
1093
+ let {
1094
+ data,
1095
+ register,
1096
+ unregister
1097
+ } = fetchersCtx;
1098
+ // Register/deregister with FetchersContext
1097
1099
  React.useEffect(() => {
1098
- // Is this busted when the React team gets real weird and calls effects
1099
- // twice on mount? We really just need to garbage collect here when this
1100
- // fetcher is no longer around.
1101
- return () => {
1102
- if (!router) {
1103
- console.warn("No router available to clean up from useFetcher()");
1104
- return;
1105
- }
1106
- router.deleteFetcher(fetcherKey);
1107
- };
1108
- }, [router, fetcherKey]);
1109
- return fetcherWithComponents;
1100
+ register(fetcherKey);
1101
+ return () => unregister(fetcherKey);
1102
+ }, [fetcherKey, register, unregister]);
1103
+ // Fetcher additions
1104
+ let load = React.useCallback(href => {
1105
+ !routeId ? process.env.NODE_ENV !== "production" ? UNSAFE_invariant(false, "fetcher.load routeId unavailable") : UNSAFE_invariant(false) : void 0;
1106
+ router.fetch(fetcherKey, routeId, href);
1107
+ }, [fetcherKey, routeId, router]);
1108
+ let submitImpl = useSubmit();
1109
+ let submit = React.useCallback((target, opts) => {
1110
+ submitImpl(target, _extends({}, opts, {
1111
+ navigate: false,
1112
+ fetcherKey
1113
+ }));
1114
+ }, [fetcherKey, submitImpl]);
1115
+ let Form = React.useMemo(() => {
1116
+ let FetcherForm = /*#__PURE__*/React.forwardRef((props, ref) => {
1117
+ return /*#__PURE__*/React.createElement(FormImpl, _extends({}, props, {
1118
+ navigate: false,
1119
+ fetcherKey: fetcherKey,
1120
+ ref: ref,
1121
+ submit: submit
1122
+ }));
1123
+ });
1124
+ if (process.env.NODE_ENV !== "production") {
1125
+ FetcherForm.displayName = "fetcher.Form";
1126
+ }
1127
+ return FetcherForm;
1128
+ }, [fetcherKey, submit]);
1129
+ return React.useMemo(() => {
1130
+ // Prefer the fetcher from `state` not `router.state` since DataRouterContext
1131
+ // is memoized so this ensures we update on fetcher state updates
1132
+ let fetcher = fetcherKey ? state.fetchers.get(fetcherKey) || IDLE_FETCHER : IDLE_FETCHER;
1133
+ return _extends({
1134
+ Form,
1135
+ submit,
1136
+ load
1137
+ }, fetcher, {
1138
+ data: data.get(fetcherKey)
1139
+ });
1140
+ }, [Form, data, fetcherKey, load, state.fetchers, submit]);
1110
1141
  }
1111
1142
  /**
1112
1143
  * Provides all fetchers currently on the page. Useful for layouts and parent
@@ -1330,5 +1361,5 @@ function useViewTransitionState(to, opts) {
1330
1361
  }
1331
1362
  //#endregion
1332
1363
 
1333
- 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 };
1364
+ 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 };
1334
1365
  //# sourceMappingURL=index.js.map