Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
14,934 changes: 14,934 additions & 0 deletions package-lock.json

Large diffs are not rendered by default.

6 changes: 3 additions & 3 deletions src/components/Layout/Page.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -144,11 +144,11 @@ export function Page({
<div
className={cn(
hasColumns &&
'grid grid-cols-only-content lg:grid-cols-sidebar-content 2xl:grid-cols-sidebar-content-toc'
'grid grid-cols-only-content md:grid-cols-sidebar-content lg:grid-cols-sidebar-content 2xl:grid-cols-sidebar-content-toc'
)}>
{showSidebar && (
<div className="lg:-mt-16 z-10">
<div className="fixed top-0 py-0 shadow lg:pt-16 lg:sticky start-0 end-0 lg:shadow-none">
<div className="md:-mt-16 z-10">
<div className="fixed top-0 py-0 shadow md:pt-16 md:sticky start-0 end-0 md:shadow-none">
<SidebarNav
key={section}
routeTree={routeTree}
Expand Down
10 changes: 5 additions & 5 deletions src/components/Layout/SidebarNav/SidebarNav.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -31,21 +31,21 @@ export default function SidebarNav({
return (
<div
className={cn(
'sticky top-0 lg:bottom-0 lg:h-[calc(100vh-4rem)] flex flex-col'
'sticky top-0 md:bottom-0 md:h-[calc(100vh-4rem)] flex flex-col'
)}>
<div
className="overflow-y-scroll no-bg-scrollbar lg:w-[342px] grow bg-wash dark:bg-wash-dark"
className="overflow-y-scroll no-bg-scrollbar md:w-full grow bg-wash dark:bg-wash-dark"
style={{
overscrollBehavior: 'contain',
}}>
<aside
className={cn(
`lg:grow flex-col w-full pb-8 lg:pb-0 lg:max-w-custom-xs z-10 hidden lg:block`
`md:grow flex-col w-full pb-8 md:pb-0 md:max-w-none z-10 hidden md:block`
)}>
<nav
role="navigation"
style={{'--bg-opacity': '.2'} as React.CSSProperties} // Need to cast here because CSS vars aren't considered valid in TS types (cuz they could be anything)
className="w-full pt-6 scrolling-touch lg:h-auto grow pe-0 lg:pe-5 lg:pb-16 md:pt-4 lg:pt-4 scrolling-gpu">
className="w-full pt-6 scrolling-touch md:h-auto grow pe-0 md:pe-5 md:pb-16 md:pt-4 scrolling-gpu">
{/* No fallback UI so need to be careful not to suspend directly inside. */}
<Suspense fallback={null}>
<SidebarRouteTree
Expand All @@ -56,7 +56,7 @@ export default function SidebarNav({
</Suspense>
<div className="h-20" />
</nav>
<div className="fixed bottom-0 hidden lg:block">
<div className="fixed bottom-0 hidden md:block">
<Feedback />
</div>
</aside>
Expand Down
6 changes: 3 additions & 3 deletions src/content/learn/choosing-the-state-structure.md
Original file line number Diff line number Diff line change
Expand Up @@ -355,7 +355,7 @@ function Message({ messageColor }) {

Here, a `color` state variable is initialized to the `messageColor` prop. The problem is that **if the parent component passes a different value of `messageColor` later (for example, `'red'` instead of `'blue'`), the `color` *state variable* would not be updated!** The state is only initialized during the first render.

This is why "mirroring" some prop in a state variable can lead to confusion. Instead, use the `messageColor` prop directly in your code. If you want to give it a shorter name, use a constant:
This is why &ldquo;mirroring&rdquo; some prop in a state variable can lead to confusion. Instead, use the `messageColor` prop directly in your code. If you want to give it a shorter name, use a constant:

```js
function Message({ messageColor }) {
Expand All @@ -364,7 +364,7 @@ function Message({ messageColor }) {

This way it won't get out of sync with the prop passed from the parent component.

"Mirroring" props into state only makes sense when you *want* to ignore all updates for a specific prop. By convention, start the prop name with `initial` or `default` to clarify that its new values are ignored:
&ldquo;Mirroring&rdquo; props into state only makes sense when you *want* to ignore all updates for a specific prop. By convention, start the prop name with `initial` or `default` to clarify that its new values are ignored:

```js
function Message({ initialColor }) {
Expand Down Expand Up @@ -2826,4 +2826,4 @@ Keep in mind that you [should not mutate objects in state](/learn/updating-objec

</Solution>

</Challenges>
</Challenges>
54 changes: 53 additions & 1 deletion src/content/reference/rsc/server-components.md
Original file line number Diff line number Diff line change
Expand Up @@ -183,7 +183,7 @@ The bundler then combines the data, rendered Server Components and dynamic Clien
</div>
```

Server Components can be made dynamic by re-fetching them from a server, where they can access the data and render again. This new application architecture combines the simple request/response mental model of server-centric Multi-Page Apps with the seamless interactivity of client-centric Single-Page Apps, giving you the best of both worlds.
Server Components can be made dynamic by re-fetching them from a server, where they can access the data and render again. This new application architecture combines the simple "request/response" mental model of server-centric Multi-Page Apps with the seamless interactivity of client-centric Single-Page Apps, giving you the best of both worlds.

### Adding interactivity to Server Components {/*adding-interactivity-to-server-components*/}

Expand Down Expand Up @@ -300,3 +300,55 @@ function Comments({commentsPromise}) {
The `note` content is important data for the page to render, so we `await` it on the server. The comments are below the fold and lower-priority, so we start the promise on the server, and wait for it on the client with the `use` API. This will Suspend on the client, without blocking the `note` content from rendering.

Since async components are not supported on the client, we await the promise with `use`.

<Note>

#### Alternative: Manual Promise handling in Client Components {/*alternative-manual-promise-handling*/}

While the `use()` hook provides seamless integration with Suspense boundaries, you can also handle Promises manually in Client Components using traditional React patterns with `useEffect` and `useState`. This approach gives you more control over loading states and error handling:

```js
// Client Component
"use client";
import { useState, useEffect } from 'react';

function Comments({commentsPromise}) {
const [comments, setComments] = useState(null);
const [error, setError] = useState(null);

useEffect(() => {
let cancelled = false;

commentsPromise
.then(data => {
if (!cancelled) {
setComments(data);
}
})
.catch(err => {
if (!cancelled) {
setError(err);
}
});

return () => {
cancelled = true;
};
}, [commentsPromise]);

if (error) return <p>Error loading comments: {error.message}</p>;
if (!comments) return <p>Loading comments...</p>;

return comments.map(comment => <p key={comment.id}>{comment.text}</p>);
}
```

This pattern is useful when you need:
- Custom loading indicators without Suspense boundaries
- Granular error handling at the component level
- To update parts of the UI progressively as data arrives
- To maintain existing component patterns while adopting Server Components

Both approaches are valid. Choose `use()` for simpler code that works with Suspense, or manual handling when you need more control over the loading experience.

</Note>
6 changes: 5 additions & 1 deletion src/utils/compileMDX.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@ import {MDXComponents} from 'components/MDX/MDXComponents';

// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
// ~~~~ IMPORTANT: BUMP THIS IF YOU CHANGE ANY CODE BELOW ~~~
const DISK_CACHE_BREAKER = 10;
const DISK_CACHE_BREAKER = 11;
// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~

export default async function compileMDX(
Expand Down Expand Up @@ -99,6 +99,10 @@ export default async function compileMDX(
const fakeRequire = (name: string) => {
if (name === 'react/jsx-runtime') {
return require('react/jsx-runtime');
} else if (name === 'react/jsx-dev-runtime') {
// In development builds Babel may compile to jsxDEV from 'react/jsx-dev-runtime'
// Ensure we return the correct dev runtime to avoid jsxDEV being undefined
return require('react/jsx-dev-runtime');
} else {
// For each fake MDX import, give back the string component name.
// It will get serialized later.
Expand Down
4 changes: 2 additions & 2 deletions tailwind.config.js
Original file line number Diff line number Diff line change
Expand Up @@ -154,8 +154,8 @@ module.exports = {
colors,
gridTemplateColumns: {
'only-content': 'auto',
'sidebar-content': '20rem auto',
'sidebar-content-toc': '20rem auto 20rem',
'sidebar-content': 'minmax(16rem, 20rem) auto',
'sidebar-content-toc': 'minmax(16rem, 20rem) auto minmax(16rem, 20rem)',
},
},
},
Expand Down
Loading
Loading