react-router-dom-v5-compat 6.2.2 → 6.4.0-pre.10

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 ADDED
@@ -0,0 +1,62 @@
1
+ # react-router-dom-v5-compat
2
+
3
+ ## 6.4.0-pre.10
4
+
5
+ ### Patch Changes
6
+
7
+ - Updated dependencies
8
+ - react-router@6.4.0-pre.10
9
+ - react-router-dom@6.4.0-pre.10
10
+
11
+ ## 6.4.0-pre.9
12
+
13
+ ### Patch Changes
14
+
15
+ - Updated dependencies
16
+ - react-router@6.4.0-pre.9
17
+ - react-router-dom@6.4.0-pre.9
18
+
19
+ ## 6.4.0-pre.8
20
+
21
+ ### Patch Changes
22
+
23
+ - Updated dependencies
24
+ - react-router@6.4.0-pre.8
25
+ - react-router-dom@6.4.0-pre.8
26
+
27
+ ## 6.4.0-pre.7
28
+
29
+ ### Patch Changes
30
+
31
+ - Updated dependencies
32
+ - `react-router@6.4.0-pre.7`
33
+ - `react-router-dom@6.4.0-pre.7`
34
+
35
+ ## 6.4.0-pre.6
36
+
37
+ ### Patch Changes
38
+
39
+ - Fix `react-router-dom` peer dependency version
40
+ - Updated dependencies
41
+ - `react-router@6.4.0-pre.6`
42
+ - `react-router-dom@6.4.0-pre.6`
43
+
44
+ ## 6.4.0-pre.5
45
+
46
+ ### Patch Changes
47
+
48
+ - Updated dependencies
49
+ - `react-router@6.4.0-pre.5`
50
+ - `react-router-dom@6.4.0-pre.5`
51
+
52
+ ## 6.4.0-pre.4
53
+
54
+ ### Patch Changes
55
+
56
+ - Fix missing `dist` files
57
+
58
+ ## 6.4.0-pre.3
59
+
60
+ ### Patch Changes
61
+
62
+ - Updated dependencies
package/LICENSE.md CHANGED
@@ -1,7 +1,7 @@
1
1
  MIT License
2
2
 
3
3
  Copyright (c) React Training 2015-2019
4
- Copyright (c) Remix Software 2020-2021
4
+ Copyright (c) Remix Software 2020-2022
5
5
 
6
6
  Permission is hereby granted, free of charge, to any person obtaining a copy
7
7
  of this software and associated documentation files (the "Software"), to deal
package/README.md CHANGED
@@ -1,3 +1,400 @@
1
1
  # React Router DOM Compat v5
2
2
 
3
- TODO
3
+ This package enables React Router web apps to incrementally migrate to the latest API in v6 by running it in parallel with v5. It is a copy of v6 with an extra couple of components to keep the two in sync.
4
+
5
+ ## Incremental Migration
6
+
7
+ Instead of upgrading and updating all of your code at once (which is incredibly difficult and prone to bugs), this strategy enables you to upgrade one component, one hook, and one route at a time by running both v5 and v6 in parallel. Any code you haven't touched is still running the very same code it was before. Once all components are exclusively using the v6 APIs, your app no longer needs the compatibility package and is running on v6.
8
+
9
+ It looks something like this:
10
+
11
+ - Setup the `CompatRouter`
12
+ - Change a `<Route>` inside of a `<Switch>` to a `<CompatRoute>`
13
+ - Update all APIs inside this route element tree to v6 APIs one at a time
14
+ - Repeat for all routes in the `<Switch>`
15
+ - Convert the `<Switch>` to a `<Routes>`
16
+ - Repeat for all ancestor `<Switch>`s
17
+ - Update `<Links>`
18
+ - You're done!
19
+
20
+ ## Setting up
21
+
22
+ These are the most common cases, be sure to read the v6 docs to figure out how to do anything not shown here.
23
+
24
+ Please [open a discussion on GitHub][discussion] if you're stuck, we'll be happy to help. We would also love for this GitHub Q&A to fill up with migration tips for the entire community, so feel free to add your tips even when you're not stuck!
25
+
26
+ ### 1) Upgrade your app to React 16.8+
27
+
28
+ React Router v6 has been rewritten with React Hooks, significantly improving bundle sizes and composition. You will need to upgrade to 16.8+ in order to migrate to React Router v6.
29
+
30
+ You can read the [Hooks Adoption Strategy](https://reactjs.org/docs/hooks-faq.html#adoption-strategy) from the React docs for help there.
31
+
32
+ ### 2) Install Compatibility Package
33
+
34
+ 👉 Install the package
35
+
36
+ ```sh
37
+ npm install react-router-dom-v5-compat
38
+ ```
39
+
40
+ This package includes the v6 API so that you can run it in parallel with v5.
41
+
42
+ ### 3) Render the Compatibility Router
43
+
44
+ The compatibility package includes a special `CompatRouter` that synchronizes the v5 and v6 APIs state so that both APIs are available.
45
+
46
+ 👉 Render the `<CompatRouter>` directly below your v5 `<BrowserRouter>`.
47
+
48
+ ```diff
49
+ import { BrowserRouter } from "react-router-dom";
50
+ +import { CompatRouter } from "react-router-dom-v5-compat";
51
+
52
+ export function App() {
53
+ return (
54
+ <BrowserRouter>
55
+ + <CompatRouter>
56
+ <Switch>
57
+ <Route path="/" exact component={Home} />
58
+ {/* ... */}
59
+ </Switch>
60
+ + </CompatRouter>
61
+ </BrowserRouter>
62
+ );
63
+ }
64
+ ```
65
+
66
+ For the curious, this component accesses the `history` from v5, sets up a listener, and then renders a "controlled" v6 `<Router>`. This way both v5 and v6 APIs are talking to the same `history` instance.
67
+
68
+ ### 4) Commit and Ship!
69
+
70
+ The whole point of this package is to allow you to incrementally migrate your code instead of a giant, risky upgrade that often halts any other feature work.
71
+
72
+ 👉 Commit the changes and ship!
73
+
74
+ ```sh
75
+ git add .
76
+ git commit -m 'setup router compatibility package'
77
+ # of course this may be different for you
78
+ git push origin main
79
+ ```
80
+
81
+ It's not much yet, but now you're ready.
82
+
83
+ ## Migration Strategy
84
+
85
+ The migration is easiest if you start from the bottom of your component tree and climb up each branch to the top.
86
+
87
+ You can start at the top, too, but then you can't migrate an entire branch of your UI to v6 completely which makes it tempting to keep using v5 APIs when working in any part of your app: "two steps forward, one step back". By migrating an entire Route's element tree to v6, new feature work there is less likely to pull in the v5 APIs.
88
+
89
+ ### 1) Render CompatRoute elements inside of Switch
90
+
91
+ 👉 Change `<Route>` to `<CompatRoute>`
92
+
93
+ ```diff
94
+ import { Route } from "react-router-dom";
95
+ + import { CompatRoute } from "react-router-dom-v5-compat";
96
+
97
+ export function SomComp() {
98
+ return (
99
+ <Switch>
100
+ - <Route path="/project/:id" component={Project} />
101
+ + <CompatRoute path="/project/:id" component={Project} />
102
+ </Switch>
103
+ )
104
+ }
105
+ ```
106
+
107
+ `<CompatRoute>` renders a v5 `<Route>` wrapped inside of a v6 context. This is the special sauce that makes both APIs available to the component tree inside of this route.
108
+
109
+ ⚠️️ You can only use `CompatRoute` inside of a `Switch`, it will not work for Routes that are rendered outside of `<Switch>`. Depending on the use case, there will be a hook in v6 to meet it.
110
+
111
+ ⚠️ You can't use regular expressions or optional params in v6 route paths. Instead, repeat the route with the extra params/regex patterns you're trying to match.
112
+
113
+ ```diff
114
+ - <Route path="/one/:two?" element={Comp} />
115
+ + <CompatRoute path="/one/:two" element={Comp} />
116
+ + <CompatRoute path="/one" element={Comp} />
117
+ ```
118
+
119
+ ### 2) Change component code use v6 instead of v5 APIs
120
+
121
+ This route now has both v5 and v6 routing contexts, so we can start migrating component code to v6.
122
+
123
+ If the component is a class component, you'll need to convert it to a function component first so that you can use hooks.
124
+
125
+ 👉 Read from v6 `useParams()` instead of v5 `props.match`
126
+
127
+ ```diff
128
+ + import { useParams } from "react-router-dom-v5-compat";
129
+
130
+ function Project(props) {
131
+ - const { params } = props.match;
132
+ + const params = useParams();
133
+ // ...
134
+ }
135
+ ```
136
+
137
+ 👉 Commit and ship!
138
+
139
+ ```sh
140
+ git add .
141
+ git commit -m "chore: RR v5 props.match -> v6 useParams"
142
+ git push origin main
143
+ ```
144
+
145
+ This component is now using both APIs at the same time. Every small change can be committed and shipped. No need for a long running branch that makes you want to quit your job, build a cabin in the woods, and live off of squirrels and papago lilies.
146
+
147
+ 👉 Read from v6 `useLocation()` instead of v5 `props.location`
148
+
149
+ ```diff
150
+ + import { useLocation } from "react-router-dom-v5-compat";
151
+
152
+ function Project(props) {
153
+ - const location = props.location;
154
+ + const location = useLocation();
155
+ // ...
156
+ }
157
+ ```
158
+
159
+ 👉 Use `navigate` instead of `history`
160
+
161
+ ```diff
162
+ + import { useNavigate } from "react-router-dom-v5-compat";
163
+
164
+ function Project(props) {
165
+ - const history = props.history;
166
+ + const navigate = useNavigate();
167
+
168
+ return (
169
+ <div>
170
+ <MenuList>
171
+ <MenuItem onClick={() => {
172
+ - history.push("/elsewhere");
173
+ + navigate("/elsewhere");
174
+
175
+ - history.replace("/elsewhere");
176
+ + navigate("/elsewhere", { replace: true });
177
+
178
+ - history.go(-1);
179
+ + navigate(-1);
180
+ }} />
181
+ </MenuList>
182
+ </div>
183
+ )
184
+ }
185
+ ```
186
+
187
+ There are more APIs you may be accessing, but these are the most common. Again, [open a discussion on GitHub][discussion] if you're stuck and we'll do our best to help out.
188
+
189
+ ### 3) (Maybe) Update Links and NavLinks
190
+
191
+ Some links may be building on `match.url` to link to deeper URLs without needing to know the portion of the URL before them. You no longer need to build the path manually, React Router v6 supports relative links.
192
+
193
+ 👉 Update links to use relative `to` values
194
+
195
+ ```diff
196
+ - import { Link } from "react-router-dom";
197
+ + import { Link } from "react-router-dom-v5-compat";
198
+
199
+ function Project(props) {
200
+ return (
201
+ <div>
202
+ - <Link to={`${props.match.url}/edit`} />
203
+ + <Link to="edit" />
204
+ </div>
205
+ )
206
+ }
207
+ ```
208
+
209
+ The way to define active className and style props has been simplified to a callback to avoid specificity issues with CSS:
210
+
211
+ 👉 Update nav links
212
+
213
+ ```diff
214
+ - import { NavLink } from "react-router-dom";
215
+ + import { NavLink } from "react-router-dom-v5-compat";
216
+
217
+ function Project(props) {
218
+ return (
219
+ <div>
220
+ - <NavLink exact to="/dashboard" />
221
+ + <NavLink end to="/dashboard" />
222
+
223
+ - <NavLink activeClassName="blue" className="red" />
224
+ + <NavLink className={({ isActive }) => isActive ? "blue" : "red" } />
225
+
226
+ - <NavLink activeStyle={{ color: "blue" }} style={{ color: "red" }} />
227
+ + <NavLink style={({ isActive }) => ({ color: isActive ? "blue" : "red" }) />
228
+ </div>
229
+ )
230
+ }
231
+ ```
232
+
233
+ ### 4) Convert `Switch` to `Routes`
234
+
235
+ Once every descendant component in a `<Switch>` has been migrated to v6, you can convert the `<Switch>` to `<Routes>` and change the `<CompatRoute>` elements to v6 `<Route>` elements.
236
+
237
+ 👉 Convert `<Switch>` to `<Routes>` and `<CompatRoute>` to v6 `<Route>`
238
+
239
+ ```diff
240
+ import { Routes, Route } from "react-router-dom-v5-compat";
241
+ - import { Switch, Route } from "react-router-dom"
242
+
243
+ - <Switch>
244
+ - <CompatRoute path="/" exact component={Home} />
245
+ - <CompatRoute path="/projects/:projectId" component={Project} />
246
+ - </Switch>
247
+ + <Routes>
248
+ + <Route path="/" element={<Home />} />
249
+ + <Route path="projects/:projectId" element={<Project />} />
250
+ + </Routes>
251
+ ```
252
+
253
+ BAM 💥 This entire branch of your UI is migrated to v6!
254
+
255
+ ### 5) Rinse and Repeat up the tree
256
+
257
+ Once your deepest `Switch` components are converted, go up to their parent `<Switch>` and repeat the process. Keep doing this all the way up the tree until all components are migrated to v6 APIs.
258
+
259
+ When you convert a `<Switch>` to `<Routes>` that has descendant `<Routes>` deeper in its tree, there are a couple things you need to do in both places for everything to continue matching correctly.
260
+
261
+ 👉️ Add splat paths to any `<Route>` with a **descendant** `<Routes>`
262
+
263
+ ```diff
264
+ function Root() {
265
+ return (
266
+ <Routes>
267
+ - <Route path="/projects" element={<Projects />} />
268
+ + <Route path="/projects/*" element={<Projects />} />
269
+ </Routes>
270
+ );
271
+ }
272
+ ```
273
+
274
+ This ensures deeper URLs like `/projects/123` continue to match that route. Note that this isn't needed if the route doesn't have any descendant `<Routes>`.
275
+
276
+ 👉 Convert route paths from absolute to relative paths
277
+
278
+ ```diff
279
+ - function Projects(props) {
280
+ - let { match } = props
281
+ function Projects() {
282
+ return (
283
+ <div>
284
+ <h1>Projects</h1>
285
+ <Routes>
286
+ - <Route path={match.path + "/activity"} element={<ProjectsActivity />} />
287
+ - <Route path={match.path + "/:projectId"} element={<Project />} />
288
+ - <Route path={match.path + "/:projectId/edit"} element={<EditProject />} />
289
+ + <Route path="activity" element={<ProjectsActivity />} />
290
+ + <Route path=":projectId" element={<Project />} />
291
+ + <Route path=":projectId/edit" element={<EditProject />} />
292
+ </Routes>
293
+ </div>
294
+ );
295
+ }
296
+ ```
297
+
298
+ Usually descendant Switch (and now Routes) were using the ancestor `match.path` to build their entire path. When the ancestor Switch is converted to `<Routes>` you no longer need to do this this manually, it happens automatically. Also, if you don't change them to relative paths, they will no longer match, so you need to do this step.
299
+
300
+ ### 6) Remove the compatibility package!
301
+
302
+ Once you've converted all of your code you can remove the compatibility package and install React Router DOM v6 directly. We have to do a few things all at once to finish this off.
303
+
304
+ 👉 Remove the compatibility package
305
+
306
+ ```sh
307
+ npm uninstall react-router-dom-v5-compat
308
+ ```
309
+
310
+ 👉 Uninstall `react-router` and `history`
311
+
312
+ v6 no longer requires history or react-router to be peer dependencies (they're normal dependencies now), so you'll need to uninstall them
313
+
314
+ ```
315
+ npm uninstall react-router history
316
+ ```
317
+
318
+ 👉 Install React Router v6
319
+
320
+ ```sh
321
+ npm install react-router-dom@6
322
+ ```
323
+
324
+ 👉 Remove the `CompatRouter`
325
+
326
+ ```diff
327
+ import { BrowserRouter } from "react-router-dom";
328
+ - import { CompatRouter } from "react-router-dom-v5-compat";
329
+
330
+ export function App() {
331
+ return (
332
+ <BrowserRouter>
333
+ - <CompatRouter>
334
+ <Routes>
335
+ <Route path="/" element={<Home />} />
336
+ {/* ... */}
337
+ </Routes>
338
+ - </CompatRouter>
339
+ </BrowserRouter>
340
+ );
341
+ }
342
+ ```
343
+
344
+ Note that `BrowserRouter` is now the v6 browser router.
345
+
346
+ 👉 Change all compat imports to "react-router-dom"
347
+
348
+ You should be able to a find/replace across the project to change all instances of "react-router-dom-v5-compat" to "react-router-dom"
349
+
350
+ ```sh
351
+ # Change `src` to wherever your source modules live
352
+ # Also strap on a fake neckbeard cause it's shell scripting time
353
+ git grep -lz src | xargs -0 sed -i '' -e 's/react-router-dom-v5-compat/react-router-dom/g'
354
+ ```
355
+
356
+ ### 7) Optional: lift `Routes` up to single route config
357
+
358
+ This part is optional (but you'll want it when the React Router data APIs ship).
359
+
360
+ Once you've converted all of your app to v6, you can lift every `<Routes>` to the top of the app and replace it with an `<Outlet>`. React Router v6 has a concept of "nested routes".
361
+
362
+ 👉 Replace descendant `<Routes>` with `<Outlet/>`
363
+
364
+ ```diff
365
+ - <Routes>
366
+ - <Route path="one" />
367
+ - <Route path="two" />
368
+ - </Routes>
369
+ + <Outlet />
370
+ ```
371
+
372
+ 👉 Lift the `<Route>` elements to the ancestor `<Routes>`
373
+
374
+ ```diff
375
+ <Routes>
376
+ <Route path="three" />
377
+ <Route path="four" />
378
+ + <Route path="one" />
379
+ + <Route path="two" />
380
+ </Routes>
381
+ ```
382
+
383
+ If you had splat paths for descendant routes, you can remove them when the descendant routes lift up to the same route configuration:
384
+
385
+ ```diff
386
+ <Routes>
387
+ - <Route path="projects/*">
388
+ + <Route path="projects">
389
+ <Route path="activity" element={<ProjectsActivity />} />
390
+ <Route path=":projectId" element={<Project />} />
391
+ <Route path=":projectId/edit" element={<EditProject />} />
392
+ </Route>
393
+ </Routes>
394
+ ```
395
+
396
+ That's it, you're done 🙌
397
+
398
+ Don't forget to [open a discussion on GitHub][discussion] if you're stuck, add your own tips, and help others with their questions 🙏
399
+
400
+ [discussion]: https://github.com/remix-run/react-router/discussions/new?category=v5-to-v6-migration
@@ -25,7 +25,7 @@
25
25
  * - TSC needs to generate the types, and it has to derive the output paths from
26
26
  * the import paths. If we have a weird require *outside of this package* to
27
27
  * "../../react-router-dom" it's going to generate types from the common root
28
- * of all module paths (Which makes sense becuase what else would it do? It
28
+ * of all module paths (Which makes sense because what else would it do? It
29
29
  * needs to write the type files next to the source files so that typescript
30
30
  * can resolve the types for tooling in the same location as the modules).
31
31
  * Because tsc isn't as flexible as rollup, we have no control over this
@@ -46,7 +46,7 @@
46
46
  * would break. We could stop doing two bundles in v6 "react-router-dom" and
47
47
  * deprecate the deep require if we wanted to avoid the duplication here.
48
48
  */
49
- export type { Hash, Location, Path, To, MemoryRouterProps, NavigateFunction, NavigateOptions, NavigateProps, Navigator, OutletProps, Params, PathMatch, RouteMatch, RouteObject, RouteProps, PathRouteProps, LayoutRouteProps, IndexRouteProps, RouterProps, Pathname, Search, RoutesProps, } from "./react-router-dom";
49
+ export type { Hash, Location, Path, To, MemoryRouterProps, NavigateFunction, NavigateOptions, NavigateProps, Navigator, OutletProps, Params, ParamParseKey, PathMatch, RouteMatch, RouteObject, RouteProps, PathRouteProps, LayoutRouteProps, IndexRouteProps, RouterProps, Pathname, Search, RoutesProps, } from "./react-router-dom";
50
50
  export { BrowserRouter, HashRouter, Link, MemoryRouter, NavLink, Navigate, NavigationType, Outlet, Route, Router, Routes, UNSAFE_LocationContext, UNSAFE_NavigationContext, UNSAFE_RouteContext, createPath, createRoutesFromChildren, createSearchParams, generatePath, matchPath, matchRoutes, parsePath, renderMatches, resolvePath, unstable_HistoryRouter, useHref, useInRouterContext, useLinkClickHandler, useLocation, useMatch, useNavigate, useNavigationType, useOutlet, useOutletContext, useParams, useResolvedPath, useRoutes, useSearchParams, } from "./react-router-dom";
51
51
  export type { StaticRouterProps } from "./lib/components";
52
- export { CompatRouter, StaticRouter } from "./lib/components";
52
+ export { CompatRouter, CompatRoute, StaticRouter } from "./lib/components";