diff --git a/src/chapter8/01-setup.md b/src/chapter8/01-setup.md
index c9cb6b1..1b6154c 100644
--- a/src/chapter8/01-setup.md
+++ b/src/chapter8/01-setup.md
@@ -1,10 +1,12 @@
## Setup
-
` tag that you already know.
However, this component does some additional things, like prefetching (i.e. preloading routes in the background).
It also changes the way navigation works (we will talk more about this in the next sections).
-Here is how you could link the About page from the home page:
+For example, you could add a link to the `/about` page from the `/` page by changing the content in `page.tsx` to this:
```jsx
import Link from 'next/link';
diff --git a/src/chapter8/03-more-on-routes.md b/src/chapter8/03-more-on-routes.md
index 12692c5..d3ff5d0 100644
--- a/src/chapter8/03-more-on-routes.md
+++ b/src/chapter8/03-more-on-routes.md
@@ -1,6 +1,6 @@
## More on Routes
- Why do Next.js routes make terrible secret agents?
Because they keep exposing endpoints.
- From "1000 programming dad-jokes"
+ Why do Next.js routes make terrible secret agents?
Because they keep exposing endpoints.
— From "1000 programming dad-jokes"
### Dynamic Routes
@@ -9,9 +9,9 @@ Let's say you want to add a route that displays a task with a certain ID at `/ta
For example, you might wish to display a task with the ID `1` at `/task/1` and a task with the ID `2` at `/task/2`.
Of course, since tasks are added and deleted by the user, you can't know all of the IDs beforehand.
-This where dynamic routes come in.
+This is where dynamic routes come in.
-Create a new file `task/[id]/page.tsx`:
+Create a new file `task/[id]/page.tsx` with the following content:
```jsx
export default function Task({ params }: { params: { id: string } }) {
@@ -19,7 +19,10 @@ export default function Task({ params }: { params: { id: string } }) {
}
```
-If you go to `http://localhost:3000/task/1`, you should see the following text:
+Here, you pass a `params` object that contains the `id` property.
+This `id` property will contain the ID passed in the URL.
+
+For example, if you go to `http://localhost:3000/task/1`, you should see the following text:
```
This is a task with ID 1
@@ -32,13 +35,13 @@ This is a task with ID 56789
```
Note that the `[id]` notation will only match a single segment.
-This means for example `http://localhost:3000/task/1/status` will not be matched by `task/[id]` and you will see a `404`.
+This means that e.g. `http://localhost:3000/task/1/status` will not be matched by `task/[id]` and you will see a `404`.
If you want to change this, you can use catch-all segments with `[...id]` and optional catch-all segments with `[[...id]]`.
### Route Handlers
-Route handlers basically allow you to create API routes.
+Route handlers basically allow you to create API routes (similar to what we did in the networking chapter).
Route handlers are defined by `route` files.
Let's create a new file `api/task/route.ts` and add a simple example route handler:
@@ -53,14 +56,19 @@ export async function GET() {
}
```
-Try accessing the route:
+You can try accessing the route by using `curl`:
+```sh
+curl localhost:3000/api/task
```
-$ curl localhost:3000/api/task
-{"taskId":1}
+
+This will output the following JSON:
+
+```json
+{ "taskId": 1 }
```
-You can access the request by passing a `request` argument to the function:
+You can access the request by passing a `request` argument to the function (similar to `express`):
```ts
import { NextRequest, NextResponse } from 'next/server';
@@ -77,6 +85,7 @@ export async function GET(request: NextRequest) {
If you look at your console, you will see that the request object is logged.
You can use the `request` object to access the various request properties.
+
For example, you could retrieve the cookies of the current request using `request.cookies`.
This is a special `RequestCookies` object that exposes methods that you can use to retrieve cookies:
@@ -96,11 +105,19 @@ export async function GET(request: NextRequest) {
}
```
-Try accessing the route now:
+Try accessing the route while passing it a cookie:
+```sh
+curl --cookie "language=de" localhost:3000/api/task
```
-$ curl --cookie "language=de" localhost:3000/api/task
-{"allCookies":[{"name":"language","value":"de"}],"languageCookie":{"name":"language","value":"de"}}
+
+The result will be:
+
+```json
+{
+ "allCookies": [{ "name": "language", "value": "de" }],
+ "languageCookie": { "name": "language", "value": "de" }
+}
```
Similarly you can access the headers of a request:
@@ -121,12 +138,29 @@ export async function GET(request: NextRequest) {
Try accessing the route again:
+```sh
+curl localhost:3000/api/task
```
-$ curl localhost:3000/api/task
-{"headers":[["accept","*/*"],["host","localhost:3000"],["user-agent","curl/7.81.0"],["x-forwarded-for","::ffff:127.0.0.1"],["x-forwarded-host","localhost:3000"],["x-forwarded-port","3000"],["x-forwarded-proto","http"]],"userAgent":"curl/7.81.0"}
+
+This will print the headers that are automatically set by `curl`:
+
+```json
+{
+ "headers": [
+ ["accept", "*/*"],
+ ["host", "localhost:3000"],
+ ["user-agent", "curl/7.81.0"],
+ ["x-forwarded-for", "::ffff:127.0.0.1"],
+ ["x-forwarded-host", "localhost:3000"],
+ ["x-forwarded-port", "3000"],
+ ["x-forwarded-proto", "http"]
+ ],
+ "userAgent": "curl/7.81.0"
+}
```
-You can have dynamic segments in your route handlers:
+You can have dynamic segments in your route handlers.
+Let's create a new file `api/task/[id]/route.ts`:
```ts
import { NextResponse } from 'next/server';
@@ -140,6 +174,18 @@ export async function GET(request: Request, { params }: { params: { id: string }
}
```
+Try accessing the dynamic route:
+
+```sh
+curl localhost:3000/api/task/42
+```
+
+This will return:
+
+```json
+{ "taskId": "42" }
+```
+
You can read query params from the `nextUrl.searchParams` object:
```ts
@@ -154,9 +200,14 @@ export function GET(request: NextRequest) {
}
```
-For example:
+Try accessing the route:
+```sh
+curl "localhost:3000/api/task?title=Title&description=Description"
```
-$ curl "localhost:3000/api/task?title=Title&description=Description"
-{"title":"Title"}
+
+This should return:
+
+```json
+{ "title": "Title" }
```
diff --git a/src/chapter8/04-server-and-client-components.md b/src/chapter8/04-server-and-client-components.md
index f62af46..522b68c 100644
--- a/src/chapter8/04-server-and-client-components.md
+++ b/src/chapter8/04-server-and-client-components.md
@@ -1,15 +1,16 @@
## Server and Client Components
- Why did the Next.js component get anxiety during drinking?
Because it was afraid of hydration errors.
- From "1000 programming dad-jokes"
+ Why did the Next.js component get anxiety during drinking?
Because it was afraid of hydration errors.
— From "1000 programming dad-jokes"
### Rendering
Next.js renders as much as it can on the server.
-By default the React components you write are rendered on the server side and the resulting HTML is sent to the browser.
-However, not all components can be fully rendered on the server.
+By default, the React components you write are rendered on the server side and the resulting HTML is sent to the browser.
+
+Unfortunately, not all components can be fully rendered on the server.
For example, components that require interactivity must be partially rendered on the client.
-Therefore the rendering is split into multiple stages:
+Therefore, the rendering is split into multiple stages:
First, Next.js renders as much as it can on the server.
@@ -31,13 +32,13 @@ Data fetching can be moved from the client to the server which can simplify the
This is especially beneficial for clients with slow network speeds.
Additionally, dependencies are now on the server and don't need to be served to the client.
-This helps greatly with reducing bundle sizes.
+This helps greatly with reducing how much the server needs to send to the client.
### Server Components
**Server components** are the components that are completely rendered on the server.
-For example this component is a server component:
+For example, this component is a server component:
```jsx
import * as React from 'react';
@@ -47,7 +48,7 @@ export default function Task() {
}
```
-There is no interactivity here, so this component can be rendered on the server completely.
+There is no interactivity here, so this component can and will be rendered completely on the server.
### Client Components
@@ -121,9 +122,13 @@ export default function Counter() {
}
```
-If you go to `http://localhost:3000/counter`, you will see that the message is output both on the server as well as the client.
-If you click the button, you will see that the message is output only on the client (since the component only rerenders there).
-However, if you refresh the page, you will observe that the message is again logged both to the server as well as the client.
+If you go to `http://localhost:3000/counter`, you will see that the `Rendered counter` message is output both on the server console as well as on the client console.
+That's because the component renders both on the server and on the client.
+
+However, all further interactivity happens only on the client.
+For example, if you click the button, you will see that the `Rendered counter` message is output only on the client console.
+
+However, if you refresh the page, you will observe that the `Rendered counter` message is again logged both to the server as well as the client.
### When to use what?
@@ -136,6 +141,6 @@ Use server components if:
Use client components only if:
-- you need event listeners (like `onClick`)
-- you need to use `useState`, `useEffect` or `useReducer`
-- you need to use certain browser APIs
+- you need to use event listeners (like `onClick`)
+- you need to use certain React hooks like `useState` or `useEffect`
+- you need to use certain browser functionality (like resizing the browser window)
diff --git a/src/chapter8/README.md b/src/chapter8/README.md
index 04098e5..c8450de 100644
--- a/src/chapter8/README.md
+++ b/src/chapter8/README.md
@@ -5,4 +5,4 @@
Now that you have a rough overview of React, we want to move to the server.
Next.js is a React-based framework for building full-stack applications.
-You will need to use at least version 13 of Next.js, because that introduced the App Router which is built on top of React Server Components.
+We will use Next.js 15, which includes the App Router and React Server Components.