diff --git a/docs/start/framework/route-module.md b/docs/start/framework/route-module.md
index 531169e0d1..36e504cb7e 100644
--- a/docs/start/framework/route-module.md
+++ b/docs/start/framework/route-module.md
@@ -137,7 +137,7 @@ See also:
## `clientMiddleware`
-This is the client-side equivalent of `middleware` and runs in the browser during client navigations. The only difference from server middleware is that client middleware doesn't return Responses because they're not wrapping an HTTP request on the server.
+This is the client-side equivalent of `middleware` and runs in the browser during client navigations. The only difference from server middleware is that client middleware doesn't return Responses because it's not wrapping an HTTP request on the server.
Here's an example middleware to log requests on the client:
diff --git a/docs/start/framework/testing.md b/docs/start/framework/testing.md
index dd2059f020..536f97edf8 100644
--- a/docs/start/framework/testing.md
+++ b/docs/start/framework/testing.md
@@ -80,7 +80,7 @@ test("LoginForm renders error messages", async () => {
## Using with Framework Mode Types
-It's important to note that `createRoutesStub` is designed for _unit_ testing of reusable components in your application that rely on on contextual router information (i.e., `loaderData`, `actionData`, `matches`). These components usually obtain this information via the hooks (`useLoaderData`, `useActionData`, `useMatches`) or via props passed down from the ancestor route component. We **strongly** recommend limiting your usage of `createRoutesStub` to unit testing of these types of reusable components.
+It's important to note that `createRoutesStub` is designed for _unit_ testing of reusable components in your application that rely on contextual router information (i.e., `loaderData`, `actionData`, `matches`). These components usually obtain this information via the hooks (`useLoaderData`, `useActionData`, `useMatches`) or via props passed down from the ancestor route component. We **strongly** recommend limiting your usage of `createRoutesStub` to unit testing of these types of reusable components.
`createRoutesStub` is _not designed_ for (and is arguably incompatible with) direct testing of Route components using the [`Route.\*`](../../explanation/type-safety) types available in Framework Mode. This is because the `Route.*` types are derived from your actual application - including the real `loader`/`action` functions as well as the structure of your route tree structure (which defines the `matches` type). When you use `createRoutesStub`, you are providing stubbed values for `loaderData`, `actionData`, and even your `matches` based on the route tree you pass to `createRoutesStub`. Therefore, the types won't align with the `Route.*` types and you'll get type issues trying to use a route component in a route stub.
diff --git a/docs/tutorials/address-book.md b/docs/tutorials/address-book.md
index 3e356eb455..6972c2ce1b 100644
--- a/docs/tutorials/address-book.md
+++ b/docs/tutorials/address-book.md
@@ -408,12 +408,10 @@ First we'll create and export a [`clientLoader`][client-loader] function in the
The following code has a type error in it, we'll fix it in the next section
-```tsx filename=app/root.tsx lines=[2,6-9,11-12,19-42]
+```tsx filename=app/root.tsx lines=[2,4-7,9-11,17-40]
// existing imports
import { getContacts } from "./data";
-// existing exports
-
export async function clientLoader() {
const contacts = await getContacts();
return { contacts };
@@ -646,7 +644,7 @@ export default function About() {
}
```
-👉 **Add a link to the about page in the sidebar**
+👉 **Transform the text inside the h1-tags into a link to the about page in the sidebar**
```tsx filename=app/root.tsx lines=[5-7]
export default function App() {
@@ -813,7 +811,7 @@ If you refresh the about page, you still see the loading spinner for just a spli
Inside of `react-router.config.ts`, we can add a [`prerender`][pre-rendering] array to the config to tell React Router to pre-render certain urls at build time. In this case we just want to pre-render the about page.
-```ts filename=app/react-router.config.ts lines=[5]
+```ts filename=react-router.config.ts lines=[5]
import { type Config } from "@react-router/dev/config";
export default {
@@ -838,7 +836,7 @@ If you ever do want to introduce server-side rendering into your React Router ap
👉 **Enable server-side rendering**
-```ts filename=app/react-router.config.ts lines=[2]
+```ts filename=react-router.config.ts lines=[2]
export default {
ssr: true,
prerender: ["/about"],
@@ -862,7 +860,7 @@ export async function loader() {
}
```
-Whether you set `ssr` to `true` or `false` depends on you and your users needs. Both strategies are perfectly valid. For the remainder of this tutorial we're going to use server-side rendering, but know that all rendering strategies are first class citizens in React Router.
+Whether you set `ssr` to `true` or `false` depends on you and your users' needs. Both strategies are perfectly valid. For the remainder of this tutorial we're going to use server-side rendering, but know that all rendering strategies are first class citizens in React Router.
## URL Params in Loaders
@@ -896,6 +894,10 @@ export default function Contact({
loaderData,
}: Route.ComponentProps) {
const { contact } = loaderData;
+ /* const contact = {
+ ...
+ };
+ */
// existing code
}
@@ -931,7 +933,7 @@ Now, if the user isn't found, code execution down this path stops and React Rout
We'll create our first contact in a second, but first let's talk about HTML.
-React Router emulates HTML Form navigation as the data mutation primitive, which used to be the only way prior to the JavaScript cambrian explosion. Don't be fooled by the simplicity! Forms in React Router give you the UX capabilities of client rendered apps with the simplicity of the "old school" web model.
+React Router emulates HTML Form navigation as the data mutation primitive, which used to be the only way prior to the JavaScript cambrian explosion. Don't be fooled by the simplicity! Forms in React Router give you the UX capabilities of client-rendered apps with the simplicity of the "old school" web model.
While unfamiliar to some web developers, HTML `form`s actually cause a navigation in the browser, just like clicking a link. The only difference is in the request: links can only change the URL while `form`s can also change the request method (`GET` vs. `POST`) and the request body (`POST` form data).
@@ -1094,10 +1096,11 @@ The edit route we just created already renders a `form`. All we need to do is ad
👉 **Add an `action` function to the edit route**
-```tsx filename=app/routes/edit-contact.tsx lines=[1,4,8,6-15]
+```tsx filename=app/routes/edit-contact.tsx lines=[1,5,7-15]
import { Form, redirect } from "react-router";
+// import { Form } from "react-router";
// existing imports
-
+// import { getContact } from "../data";
import { getContact, updateContact } from "../data";
export async function action({
@@ -1168,7 +1171,7 @@ export async function action({
params,
request,
}: Route.ActionArgs) {
- invariant(params.contactId, "Missing contactId param");
+ //invariant(params.contactId, "Missing contactId param"); // What is this?
const formData = await request.formData();
const updates = Object.fromEntries(formData);
await updateContact(params.contactId, updates);
@@ -1188,8 +1191,10 @@ Now that we know how to redirect, let's update the action that creates new conta
👉 **Redirect to the new record's edit page**
-```tsx filename=app/root.tsx lines=[6,12]
+```tsx filename=app/root.tsx lines=[8,14]
import {
+ Form, // not really needed anymore
+ Link, // not really needed anymore
Outlet,
Scripts,
ScrollRestoration,
@@ -1218,7 +1223,7 @@ Now that we have a bunch of records, it's not clear which one we're looking at i
```tsx filename=app/layouts/sidebar.tsx lines=[1,17-26,28]
import { Form, Link, NavLink, Outlet } from "react-router";
-
+//import { Form, Link, Outlet } from "react-router";
// existing imports and exports
export default function SidebarLayout({
@@ -1262,7 +1267,7 @@ Note that we are passing a function to `className`. When the user is at the URL
## Global Pending UI
-As the user navigates the app, React Router will _leave the old page up_ as data is loading for the next page. You may have noticed the app feels a little unresponsive as you click between the list. Let's provide the user with some feedback so the app doesn't feel unresponsive.
+As the user navigates the app, React Router will _leave the old page up_ as data is loading for the next page. You may have noticed the app seemed a little unresponsive as you clicked between the list. Let's provide the user with some feedback so the app doesn't feel unresponsive.
React Router is managing all the state behind the scenes and reveals the pieces you need to build dynamic web apps. In this case, we'll use the [`useNavigation`][use-navigation] hook.
@@ -1301,7 +1306,7 @@ export default function SidebarLayout({
[`useNavigation`][use-navigation] returns the current navigation state: it can be one of `"idle"`, `"loading"` or `"submitting"`.
-In our case, we add a `"loading"` class to the main part of the app if we're not idle. The CSS then adds a nice fade after a short delay (to avoid flickering the UI for fast loads). You could do anything you want though, like show a spinner or loading bar across the top.
+In our case, we add a `"loading"` class to the main part of the app if it's not idle. The CSS then adds a nice fade after a short delay (to avoid flickering the UI for fast loads). You could do anything you want though, like show a spinner or loading bar across the top.
@@ -1348,7 +1353,6 @@ export default [
"contacts/:contactId/destroy",
"routes/destroy-contact.tsx",
),
- // existing routes
] satisfies RouteConfig;
```
@@ -1376,7 +1380,7 @@ When the user clicks the submit button:
2. The `
);
@@ -1439,7 +1442,7 @@ Since it's not `