Skip to content

Commit

Permalink
vault backup: 2024-06-02 20:03:44
Browse files Browse the repository at this point in the history
Affected files:
content/.obsidian/plugins/recent-files-obsidian/data.json
content/.obsidian/workspace.json
content/mocs/Data Cache.md
content/mocs/React MOC.md
content/mocs/Request Memoization.md
  • Loading branch information
windsuzu committed Jun 2, 2024
1 parent ec7be06 commit 1835db4
Show file tree
Hide file tree
Showing 5 changed files with 157 additions and 36 deletions.
16 changes: 8 additions & 8 deletions content/.obsidian/plugins/recent-files-obsidian/data.json
Original file line number Diff line number Diff line change
@@ -1,5 +1,9 @@
{
"recentFiles": [
{
"basename": "Data Cache",
"path": "mocs/Data Cache.md"
},
{
"basename": "Request Memoization",
"path": "mocs/Request Memoization.md"
Expand All @@ -8,14 +12,14 @@
"basename": "React MOC",
"path": "mocs/React MOC.md"
},
{
"basename": "Server Action",
"path": "react/server-action/Server Action.md"
},
{
"basename": "useActionState (useFormState)",
"path": "react/server-action/useActionState (useFormState).md"
},
{
"basename": "Server Action",
"path": "react/server-action/Server Action.md"
},
{
"basename": "useFormStatus",
"path": "react/server-action/useFormStatus.md"
Expand Down Expand Up @@ -195,10 +199,6 @@
{
"basename": "Prepositions",
"path": "english-grammar/Prepositions.md"
},
{
"basename": "Prepositions Common Mistakes",
"path": "english-grammar/Prepositions Common Mistakes.md"
}
],
"omittedPaths": [],
Expand Down
35 changes: 11 additions & 24 deletions content/.obsidian/workspace.json
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,7 @@
"state": {
"type": "markdown",
"state": {
"file": "mocs/React MOC.md",
"file": "mocs/Data Cache.md",
"mode": "source",
"source": false
}
Expand All @@ -30,21 +30,8 @@
"source": false
}
}
},
{
"id": "64279b3e331b18e7",
"type": "leaf",
"state": {
"type": "markdown",
"state": {
"file": "react/server-action/useActionState (useFormState).md",
"mode": "source",
"source": false
}
}
}
],
"currentTab": 1
]
}
],
"direction": "vertical"
Expand Down Expand Up @@ -127,7 +114,7 @@
"state": {
"type": "localgraph",
"state": {
"file": "mocs/Request Memoization.md",
"file": "mocs/Data Cache.md",
"options": {
"collapse-filter": true,
"search": "",
Expand Down Expand Up @@ -177,7 +164,7 @@
"state": {
"type": "outline",
"state": {
"file": "mocs/Request Memoization.md"
"file": "mocs/Data Cache.md"
}
}
},
Expand Down Expand Up @@ -218,7 +205,7 @@
"state": {
"type": "file-properties",
"state": {
"file": "mocs/Request Memoization.md"
"file": "mocs/Data Cache.md"
}
}
},
Expand All @@ -228,7 +215,7 @@
"state": {
"type": "backlink",
"state": {
"file": "mocs/Request Memoization.md",
"file": "mocs/Data Cache.md",
"collapseAll": false,
"extraContext": false,
"sortOrder": "alphabetical",
Expand All @@ -245,7 +232,7 @@
"state": {
"type": "outgoing-link",
"state": {
"file": "mocs/Request Memoization.md",
"file": "mocs/Data Cache.md",
"linksCollapsed": false,
"unlinkedCollapsed": false
}
Expand All @@ -271,12 +258,13 @@
"cmdr:Obsidian Git: Create backup": false
}
},
"active": "ffb49d5cb96554c3",
"active": "10a82c220b604f75",
"lastOpenFiles": [
"mocs/React MOC.md",
"mocs/Data Cache.md",
"mocs/Request Memoization.md",
"react/server-action/Server Action.md",
"mocs/React MOC.md",
"react/server-action/useActionState (useFormState).md",
"react/server-action/Server Action.md",
"react/server-action/useFormStatus.md",
"web-dev",
"browser-event/Event Delegation (event.target).md",
Expand Down Expand Up @@ -305,7 +293,6 @@
"resume/Avoid Cliches and Buzzwords on resume.md",
"english-grammar/English Grammar.md",
"mocs/CSS MOC.md",
"mocs/Backend MOC.md",
"postgresql",
"prisma",
"fish-shell",
Expand Down
84 changes: 84 additions & 0 deletions content/mocs/Data Cache.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,84 @@
---
draft: false
date: 2024-06-02 19:33
tags:
- react
- nextjs
- cache
---

By default, Next.js automatically caches data in the Data Cache for every `fetch` request in server components. The Data Cache is the last cache Next.js hits before fetching data from APIs or the database. It is also persistent across multiple requests and users.

If there are 100 users requesting the same data, Next.js will fetch it only once, store it in the Data Cache, and return it from the cache to 100 users.

```tsx {3}
export default async function Page({ params }) {
const city = params.city
const res = await fetch(`https://api.globetrotter.com/guides/${city}`)
const guideData = await res.json()

return (
<div>
<h1>{guideData.title}</h1>
<p>{guideData.content}</p>
{/* Render the guide data */}
</div>
)
}
```

For example, the `guideData` will only be fetched from the API once and stored in the data cache. All users will get the data from the data cache instead of fetching it from the API.
### Revalidation

This cache is never cleared, even if you redeploy your application. The only way to update the cache is to explicitly tell Next.js to do so using **time-based revalidation** or **on-demand revalidation.**

#### Time-based revalidation

We can tell Next.js to automatically revalidate the data in the data cache by declaring a time period. You can either declare the time as the second parameter (options) in the `fetch` function, or declare it as a config option of the page.

Next.js implements time-based revalidation with a pattern called `stale-while-revalidate`. Here is how it works:

1. `fetch` the data from the API and store it in the data cache.
2. Within 1 hour, each `fetch` returns only the data from the data cache.
3. After 1 hour, the first `fetch` returns the data from the data cache, but it also makes the request with API and updates the data cache with new data.
4. The next `fetch` returns the new data in the data cache.

```tsx title="Revalidate a fetch request"
// The cache of this fetch will be revalidated after 1 hour
const res = fetch(`https://api.globetrotter.com/guides/${city}`, {
next: { revalidate: 3600 },
})
```

```tsx title="Revalidate whole page"
// all cache of this page will be revalidated after 1 hour
export const revalidate = 3600

export default async function Page({ params }) {
const city = params.city
const res = await fetch(`https://api.globetrotter.com/guides/${city}`)
const guideData = await res.json()

return (
<div>
<h1>{guideData.title}</h1>
<p>{guideData.content}</p>
{/* Render the guide data */}
</div>
)
}
```

> [!important]
> The time period declared in the fetch function has higher priority than the one declared in the page when two methods are used at the same time.
#### On-demand Revalidation





> [!info] References
> - [Finally Master Next.js's Most Complex Feature - Caching (webdevsimplified.com)](https://blog.webdevsimplified.com/2024-01/next-js-app-router-cache/)
> - [Building Your Application: Caching | Next.js (nextjs.org)](https://nextjs.org/docs/app/building-your-application/caching)
> - [Functions: unstable_cache | Next.js (nextjs.org)](https://nextjs.org/docs/app/api-reference/functions/unstable_cache)
5 changes: 2 additions & 3 deletions content/mocs/React MOC.md
Original file line number Diff line number Diff line change
@@ -1,16 +1,15 @@
---
draft: false
date: 2024-06-02 15:24
date: 2024-06-02 17:53
tags:
- react
---

## Component Design
- [[Controlled Components]]


## Cache
- [[Request Memoization]]
- [[Data Cache]]


## Server Actions
Expand Down
53 changes: 52 additions & 1 deletion content/mocs/Request Memoization.md
Original file line number Diff line number Diff line change
@@ -1,16 +1,67 @@
---
draft: false
date: 2024-06-02 15:24
date: 2024-06-02 17:53
tags:
- react
- nextjs
- cache
---

Request memoization is more of a React feature rather than a Next.js feature. It caches `fetch` results that are made in server components **in a single render cycle**. It will return results from the cache if there are second and more `fetch` requests with same parameters (URL and options).

```tsx {8,17}
export default async function fetchUserData(userId) {
// The `fetch` function is automatically cached by Next.js
const res = await fetch(`https://api.example.com/users/${userId}`)
return res.json();
}

export default async function Page({ params }) {
const user = await fetchUserData(params.id)

return <>
<h1>{user.name}</h1>
<UserDetails id={params.id} />
</>
}

async function UserDetails({ id }) {
const user = await fetchUserData(id)
return <p>{user.name}</p>
}
```

For example, we have `Page` and `UserDetails` server components. When the `user` data is retrieved by the first `fetch` request in the `Page` component, the `user` data is also stored in the request memoization cache.

After that, the second `fetch` request in the `UserDetails` component will retrieve the stored data from the request memoization cache. The entire process happens in a single render cycle.

### Caching Non-`fetch` Requests

By default, React caches all `fetch` requests in request memoization. However, it also provides a `cache` function to wrap other non-`fetch` requests and make them behave like `fetch` requests.

```tsx
import { cache } from "react"
import { queryDatabase } from "./databaseClient"

export const fetchUserData = cache(userId => {
// Direct database query
return queryDatabase("SELECT * FROM users WHERE id = ?", [userId])
})
```

### Opting Out

If you don't want the request memoization to happen, you can pass a `signal` from the `AbortController` as a parameter to the `fetch` request. This prevents `fetch` result from being cached in the request memoization cache. However, it is not recommended to do this.

```tsx {2,4}
async function fetchUserData(userId) {
const { signal } = new AbortController()
const res = await fetch(`https://api.example.com/users/${userId}`, {
signal,
})
return res.json()
}
```

> [!info] References
> - [Finally Master Next.js's Most Complex Feature - Caching (webdevsimplified.com)](https://blog.webdevsimplified.com/2024-01/next-js-app-router-cache/)
Expand Down

0 comments on commit 1835db4

Please sign in to comment.