react-router 0.0.0-experimental-af76d50e → 0.0.0-experimental-dc8656c8

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,30 @@
1
1
  # `react-router`
2
2
 
3
+ ## 6.11.1
4
+
5
+ ### Patch Changes
6
+
7
+ - Fix usage of `Component` API within descendant `<Routes>` ([#10434](https://github.com/remix-run/react-router/pull/10434))
8
+ - Fix bug when calling `useNavigate` from `<Routes>` inside a `<RouterProvider>` ([#10432](https://github.com/remix-run/react-router/pull/10432))
9
+ - Fix usage of `<Navigate>` in strict mode when using a data router ([#10435](https://github.com/remix-run/react-router/pull/10435))
10
+ - Updated dependencies:
11
+ - `@remix-run/router@1.6.1`
12
+
13
+ ## 6.11.0
14
+
15
+ ### Patch Changes
16
+
17
+ - Log loader/action errors to the console in dev for easier stack trace evaluation ([#10286](https://github.com/remix-run/react-router/pull/10286))
18
+ - Fix bug preventing rendering of descendant `<Routes>` when `RouterProvider` errors existed ([#10374](https://github.com/remix-run/react-router/pull/10374))
19
+ - Fix inadvertent re-renders when using `Component` instead of `element` on a route definition ([#10287](https://github.com/remix-run/react-router/pull/10287))
20
+ - Fix detection of `useNavigate` in the render cycle by setting the `activeRef` in a layout effect, allowing the `navigate` function to be passed to child components and called in a `useEffect` there. ([#10394](https://github.com/remix-run/react-router/pull/10394))
21
+ - Switched from `useSyncExternalStore` to `useState` for internal `@remix-run/router` router state syncing in `<RouterProvider>`. We found some [subtle bugs](https://codesandbox.io/s/use-sync-external-store-loop-9g7b81) where router state updates got propagated _before_ other normal `useState` updates, which could lead to footguns in `useEffect` calls. ([#10377](https://github.com/remix-run/react-router/pull/10377), [#10409](https://github.com/remix-run/react-router/pull/10409))
22
+ - Allow `useRevalidator()` to resolve a loader-driven error boundary scenario ([#10369](https://github.com/remix-run/react-router/pull/10369))
23
+ - Avoid unnecessary unsubscribe/resubscribes on router state changes ([#10409](https://github.com/remix-run/react-router/pull/10409))
24
+ - When using a `RouterProvider`, `useNavigate`/`useSubmit`/`fetcher.submit` are now stable across location changes, since we can handle relative routing via the `@remix-run/router` instance and get rid of our dependence on `useLocation()`. When using `BrowserRouter`, these hooks remain unstable across location changes because they still rely on `useLocation()`. ([#10336](https://github.com/remix-run/react-router/pull/10336))
25
+ - Updated dependencies:
26
+ - `@remix-run/router@1.6.0`
27
+
3
28
  ## 6.10.0
4
29
 
5
30
  ### Minor Changes
package/LICENSE.md CHANGED
@@ -1,7 +1,8 @@
1
1
  MIT License
2
2
 
3
- Copyright (c) React Training 2015-2019
4
- Copyright (c) Remix Software 2020-2022
3
+ Copyright (c) React Training LLC 2015-2019
4
+ Copyright (c) Remix Software Inc. 2020-2021
5
+ Copyright (c) Shopify Inc. 2022-2023
5
6
 
6
7
  Permission is hereby granted, free of charge, to any person obtaining a copy
7
8
  of this software and associated documentation files (the "Software"), to deal
package/README.md CHANGED
@@ -2,9 +2,9 @@
2
2
 
3
3
  The `react-router` package is the heart of [React Router](https://github.com/remix-run/react-router) and provides all
4
4
  the core functionality for both
5
- [`react-router-dom`](/packages/react-router-dom)
5
+ [`react-router-dom`](https://github.com/remix-run/react-router/tree/main/packages/react-router-dom)
6
6
  and
7
- [`react-router-native`](/packages/react-router-native).
7
+ [`react-router-native`](https://github.com/remix-run/react-router/tree/main/packages/react-router-native).
8
8
 
9
9
  If you're using React Router, you should never `import` anything directly from
10
10
  the `react-router` package, but you should have everything you need in either
package/dist/index.js CHANGED
@@ -1,5 +1,5 @@
1
1
  /**
2
- * React Router v0.0.0-experimental-af76d50e
2
+ * React Router v0.0.0-experimental-dc8656c8
3
3
  *
4
4
  * Copyright (c) Remix Software Inc.
5
5
  *
@@ -61,7 +61,8 @@ if (process.env.NODE_ENV !== "production") {
61
61
 
62
62
  const RouteContext = /*#__PURE__*/React.createContext({
63
63
  outlet: null,
64
- matches: []
64
+ matches: [],
65
+ isDataRoute: false
65
66
  });
66
67
 
67
68
  if (process.env.NODE_ENV !== "production") {
@@ -171,23 +172,40 @@ function useMatch(pattern) {
171
172
  * The interface for the navigate() function returned from useNavigate().
172
173
  */
173
174
 
175
+ const navigateEffectWarning = "You should call navigate() in a React.useEffect(), not when " + "your component is first rendered."; // Mute warnings for calls to useNavigate in SSR environments
176
+
177
+ function useIsomorphicLayoutEffect(cb) {
178
+ let isStatic = React.useContext(NavigationContext).static;
179
+
180
+ if (!isStatic) {
181
+ // We should be able to get rid of this once react 18.3 is released
182
+ // See: https://github.com/facebook/react/pull/26395
183
+ // eslint-disable-next-line react-hooks/rules-of-hooks
184
+ React.useLayoutEffect(cb);
185
+ }
186
+ }
174
187
  /**
175
188
  * Returns an imperative method for changing the location. Used by <Link>s, but
176
189
  * may also be used by other elements to change the location.
177
190
  *
178
191
  * @see https://reactrouter.com/hooks/use-navigate
179
192
  */
193
+
194
+
180
195
  function useNavigate() {
181
- let isDataRouter = React.useContext(DataRouterContext) != null; // Conditional usage is OK here because the usage of a data router is static
196
+ let {
197
+ isDataRoute
198
+ } = React.useContext(RouteContext); // Conditional usage is OK here because the usage of a data router is static
182
199
  // eslint-disable-next-line react-hooks/rules-of-hooks
183
200
 
184
- return isDataRouter ? useNavigateStable() : useNavigateUnstable();
201
+ return isDataRoute ? useNavigateStable() : useNavigateUnstable();
185
202
  }
186
203
 
187
204
  function useNavigateUnstable() {
188
205
  !useInRouterContext() ? process.env.NODE_ENV !== "production" ? UNSAFE_invariant(false, // TODO: This error is probably because they somehow have 2 versions of the
189
206
  // router loaded. We can help them understand how to avoid that.
190
207
  "useNavigate() may be used only in the context of a <Router> component.") : UNSAFE_invariant(false) : void 0;
208
+ let dataRouterContext = React.useContext(DataRouterContext);
191
209
  let {
192
210
  basename,
193
211
  navigator
@@ -200,7 +218,7 @@ function useNavigateUnstable() {
200
218
  } = useLocation();
201
219
  let routePathnamesJson = JSON.stringify(UNSAFE_getPathContributingMatches(matches).map(match => match.pathnameBase));
202
220
  let activeRef = React.useRef(false);
203
- React.useEffect(() => {
221
+ useIsomorphicLayoutEffect(() => {
204
222
  activeRef.current = true;
205
223
  });
206
224
  let navigate = React.useCallback(function (to, options) {
@@ -208,7 +226,9 @@ function useNavigateUnstable() {
208
226
  options = {};
209
227
  }
210
228
 
211
- process.env.NODE_ENV !== "production" ? UNSAFE_warning(activeRef.current, "You should call navigate() in a React.useEffect(), not when " + "your component is first rendered.") : void 0;
229
+ process.env.NODE_ENV !== "production" ? UNSAFE_warning(activeRef.current, navigateEffectWarning) : void 0; // Short circuit here since if this happens on first render the navigate
230
+ // is useless because we haven't wired up our history listener yet
231
+
212
232
  if (!activeRef.current) return;
213
233
 
214
234
  if (typeof to === "number") {
@@ -217,16 +237,18 @@ function useNavigateUnstable() {
217
237
  }
218
238
 
219
239
  let path = resolveTo(to, JSON.parse(routePathnamesJson), locationPathname, options.relative === "path"); // If we're operating within a basename, prepend it to the pathname prior
220
- // to handing off to history. If this is a root navigation, then we
221
- // navigate to the raw basename which allows the basename to have full
222
- // control over the presence of a trailing slash on root links
240
+ // to handing off to history (but only if we're not in a data router,
241
+ // otherwise it'll prepend the basename inside of the router).
242
+ // If this is a root navigation, then we navigate to the raw basename
243
+ // which allows the basename to have full control over the presence of a
244
+ // trailing slash on root links
223
245
 
224
- if (basename !== "/") {
246
+ if (dataRouterContext == null && basename !== "/") {
225
247
  path.pathname = path.pathname === "/" ? basename : joinPaths([basename, path.pathname]);
226
248
  }
227
249
 
228
250
  (!!options.replace ? navigator.replace : navigator.push)(path, options.state, options);
229
- }, [basename, navigator, routePathnamesJson, locationPathname]);
251
+ }, [basename, navigator, routePathnamesJson, locationPathname, dataRouterContext]);
230
252
  return navigate;
231
253
  }
232
254
 
@@ -558,6 +580,14 @@ function _renderMatches(matches, parentMatches, dataRouterState) {
558
580
 
559
581
  if (error) {
560
582
  children = errorElement;
583
+ } else if (match.route.Component) {
584
+ // Note: This is a de-optimized path since React won't re-use the
585
+ // ReactElement since it's identity changes with each new
586
+ // React.createElement call. We keep this so folks can use
587
+ // `<Route Component={...}>` in `<Routes>` but generally `Component`
588
+ // usage is only advised in `RouterProvider` when we can convert it to
589
+ // `element` ahead of time.
590
+ children = /*#__PURE__*/React.createElement(match.route.Component, null);
561
591
  } else if (match.route.element) {
562
592
  children = match.route.element;
563
593
  } else {
@@ -568,7 +598,8 @@ function _renderMatches(matches, parentMatches, dataRouterState) {
568
598
  match: match,
569
599
  routeContext: {
570
600
  outlet,
571
- matches
601
+ matches,
602
+ isDataRoute: dataRouterState != null
572
603
  },
573
604
  children: children
574
605
  });
@@ -585,7 +616,8 @@ function _renderMatches(matches, parentMatches, dataRouterState) {
585
616
  children: getChildren(),
586
617
  routeContext: {
587
618
  outlet: null,
588
- matches
619
+ matches,
620
+ isDataRoute: true
589
621
  }
590
622
  }) : getChildren();
591
623
  }, null);
@@ -803,11 +835,20 @@ function useNavigateStable() {
803
835
  router
804
836
  } = useDataRouterContext(DataRouterHook.UseNavigateStable);
805
837
  let id = useCurrentRouteId(DataRouterStateHook.UseNavigateStable);
838
+ let activeRef = React.useRef(false);
839
+ useIsomorphicLayoutEffect(() => {
840
+ activeRef.current = true;
841
+ });
806
842
  let navigate = React.useCallback(function (to, options) {
807
843
  if (options === void 0) {
808
844
  options = {};
809
845
  }
810
846
 
847
+ process.env.NODE_ENV !== "production" ? UNSAFE_warning(activeRef.current, navigateEffectWarning) : void 0; // Short circuit here since if this happens on first render the navigate
848
+ // is useless because we haven't wired up our router subscriber yet
849
+
850
+ if (!activeRef.current) return;
851
+
811
852
  if (typeof to === "number") {
812
853
  router.navigate(to);
813
854
  } else {
@@ -836,16 +877,10 @@ function RouterProvider(_ref) {
836
877
  fallbackElement,
837
878
  router
838
879
  } = _ref;
839
- let [state, setState] = React.useState(router.state); // Need to use a layout effect here so we are subscribed early enough to
880
+ // Need to use a layout effect here so we are subscribed early enough to
840
881
  // pick up on any render-driven redirects/navigations (useEffect/<Navigate>)
841
-
842
- React.useLayoutEffect(() => {
843
- return router.subscribe(newState => {
844
- if (newState !== state) {
845
- setState(newState);
846
- }
847
- });
848
- }, [router, state]);
882
+ let [state, setState] = React.useState(router.state);
883
+ React.useLayoutEffect(() => router.subscribe(setState), [router, setState]);
849
884
  let navigator = React.useMemo(() => {
850
885
  return {
851
886
  createHref: router.createHref,
@@ -955,22 +990,22 @@ function Navigate(_ref4) {
955
990
  // the router loaded. We can help them understand how to avoid that.
956
991
  "<Navigate> may be used only in the context of a <Router> component.") : UNSAFE_invariant(false) : void 0;
957
992
  process.env.NODE_ENV !== "production" ? UNSAFE_warning(!React.useContext(NavigationContext).static, "<Navigate> must not be used on the initial render in a <StaticRouter>. " + "This is a no-op, but you should modify your code so the <Navigate> is " + "only ever rendered in response to some user interaction or state change.") : void 0;
958
- let dataRouterState = React.useContext(DataRouterStateContext);
959
- let navigate = useNavigate();
960
- React.useEffect(() => {
961
- // Avoid kicking off multiple navigations if we're in the middle of a
962
- // data-router navigation, since components get re-rendered when we enter
963
- // a submitting/loading state
964
- if (dataRouterState && dataRouterState.navigation.state !== "idle") {
965
- return;
966
- }
993
+ let {
994
+ matches
995
+ } = React.useContext(RouteContext);
996
+ let {
997
+ pathname: locationPathname
998
+ } = useLocation();
999
+ let navigate = useNavigate(); // Resolve the path outside of the effect so that when effects run twice in
1000
+ // StrictMode they navigate to the same place
967
1001
 
968
- navigate(to, {
969
- replace,
970
- state,
971
- relative
972
- });
973
- });
1002
+ let path = resolveTo(to, UNSAFE_getPathContributingMatches(matches).map(match => match.pathnameBase), locationPathname, relative === "path");
1003
+ let jsonPath = JSON.stringify(path);
1004
+ React.useEffect(() => navigate(JSON.parse(jsonPath), {
1005
+ replace,
1006
+ state,
1007
+ relative
1008
+ }), [navigate, jsonPath, relative, replace, state]);
974
1009
  return null;
975
1010
  }
976
1011