Skip to content

Commit 3997190

Browse files
committed
Fix broken MDX doc links
1 parent d8b2add commit 3997190

File tree

9 files changed

+52
-19
lines changed

9 files changed

+52
-19
lines changed

src/components/MDX/Link.tsx

Lines changed: 39 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,31 @@ import cn from 'classnames';
1616
import {ExternalLink} from 'components/ExternalLink';
1717
import {getMDXName} from './getMDXName';
1818

19+
const ABSOLUTE_DOC_SECTIONS = [
20+
'blog',
21+
'community',
22+
'errors',
23+
'learn',
24+
'reference',
25+
] as const;
26+
27+
function normalizeDocsHref(href: string) {
28+
if (
29+
href.startsWith('/') ||
30+
href.startsWith('#') ||
31+
href.startsWith('./') ||
32+
href.startsWith('../')
33+
) {
34+
return href;
35+
}
36+
37+
const matchesDocsPath = ABSOLUTE_DOC_SECTIONS.some(
38+
(section) => href === section || href.startsWith(`${section}/`)
39+
);
40+
41+
return matchesDocsPath ? `/${href}` : href;
42+
}
43+
1944
function Link({
2045
href,
2146
className,
@@ -36,18 +61,27 @@ function Link({
3661
if (!href) {
3762
return <a href={href} className={className} {...props} />;
3863
}
64+
65+
const normalizedHref = normalizeDocsHref(href);
66+
3967
return (
4068
<>
41-
{href.startsWith('https://') ? (
42-
<ExternalLink href={href} className={cn(classes, className)} {...props}>
69+
{normalizedHref.startsWith('https://') ? (
70+
<ExternalLink
71+
href={normalizedHref}
72+
className={cn(classes, className)}
73+
{...props}>
4374
{modifiedChildren}
4475
</ExternalLink>
45-
) : href.startsWith('#') ? (
46-
<a className={cn(classes, className)} href={href} {...props}>
76+
) : normalizedHref.startsWith('#') ? (
77+
<a className={cn(classes, className)} href={normalizedHref} {...props}>
4778
{modifiedChildren}
4879
</a>
4980
) : (
50-
<NextLink href={href} className={cn(classes, className)} {...props}>
81+
<NextLink
82+
href={normalizedHref}
83+
className={cn(classes, className)}
84+
{...props}>
5185
{modifiedChildren}
5286
</NextLink>
5387
)}

src/content/learn/preserving-and-resetting-state.md

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -18,7 +18,7 @@ State is isolated between components. React keeps track of which state belongs t
1818

1919
## State is tied to a position in the render tree {/*state-is-tied-to-a-position-in-the-tree*/}
2020

21-
React builds [render trees](learn/understanding-your-ui-as-a-tree#the-render-tree) for the component structure in your UI.
21+
React builds [render trees](/learn/understanding-your-ui-as-a-tree#the-render-tree) for the component structure in your UI.
2222

2323
When you give a component state, you might think the state "lives" inside the component. But the state is actually held inside React. React associates each piece of state it's holding with the correct component by where that component sits in the render tree.
2424

src/content/learn/react-compiler/introduction.md

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -144,7 +144,7 @@ However, if `expensivelyProcessAReallyLargeArrayOfObjects` is truly an expensive
144144
- React Compiler only memoizes React components and hooks, not every function
145145
- React Compiler's memoization is not shared across multiple components or hooks
146146

147-
So if `expensivelyProcessAReallyLargeArrayOfObjects` was used in many different components, even if the same exact items were passed down, that expensive calculation would be run repeatedly. We recommend [profiling](reference/react/useMemo#how-to-tell-if-a-calculation-is-expensive) first to see if it really is that expensive before making code more complicated.
147+
So if `expensivelyProcessAReallyLargeArrayOfObjects` was used in many different components, even if the same exact items were passed down, that expensive calculation would be run repeatedly. We recommend [profiling](/reference/react/useMemo#how-to-tell-if-a-calculation-is-expensive) first to see if it really is that expensive before making code more complicated.
148148
</DeepDive>
149149

150150
## Should I try out the compiler? {/*should-i-try-out-the-compiler*/}
@@ -188,4 +188,3 @@ This section will help you get started with React Compiler and understand how to
188188
## Additional resources {/*additional-resources*/}
189189

190190
In addition to these docs, we recommend checking the [React Compiler Working Group](https://github.com/reactwg/react-compiler) for additional information and discussion about the compiler.
191-

src/content/learn/setup.md

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -17,7 +17,7 @@ TypeScript is a popular way to add type definitions to JavaScript codebases. [Le
1717

1818
## React Developer Tools {/*react-developer-tools*/}
1919

20-
React Developer Tools is a browser extension that can inspect React components, edit props and state, and identify performance problems. Learn how to install it [here](learn/react-developer-tools).
20+
React Developer Tools is a browser extension that can inspect React components, edit props and state, and identify performance problems. Learn how to install it [here](/learn/react-developer-tools).
2121

2222
## React Compiler {/*react-compiler*/}
2323

src/content/learn/understanding-your-ui-as-a-tree.md

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -135,7 +135,7 @@ The root node in a React render tree is the [root component](/learn/importing-an
135135

136136
#### Where are the HTML tags in the render tree? {/*where-are-the-html-elements-in-the-render-tree*/}
137137

138-
You'll notice in the above render tree, there is no mention of the HTML tags that each component renders. This is because the render tree is only composed of React [components](learn/your-first-component#components-ui-building-blocks).
138+
You'll notice in the above render tree, there is no mention of the HTML tags that each component renders. This is because the render tree is only composed of React [components](/learn/your-first-component#components-ui-building-blocks).
139139

140140
React, as a UI framework, is platform agnostic. On react.dev, we showcase examples that render to the web, which uses HTML markup as its UI primitives. But a React app could just as likely render to a mobile or desktop platform, which may use different UI primitives like [UIView](https://developer.apple.com/documentation/uikit/uiview) or [FrameworkElement](https://learn.microsoft.com/en-us/dotnet/api/system.windows.frameworkelement?view=windowsdesktop-7.0).
141141

src/content/reference/react-dom/index.md

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -48,6 +48,6 @@ These APIs were removed in React 19:
4848
* [`findDOMNode`](https://18.react.dev/reference/react-dom/findDOMNode): see [alternatives](https://18.react.dev/reference/react-dom/findDOMNode#alternatives).
4949
* [`hydrate`](https://18.react.dev/reference/react-dom/hydrate): use [`hydrateRoot`](/reference/react-dom/client/hydrateRoot) instead.
5050
* [`render`](https://18.react.dev/reference/react-dom/render): use [`createRoot`](/reference/react-dom/client/createRoot) instead.
51-
* [`unmountComponentAtNode`](/reference/react-dom/unmountComponentAtNode): use [`root.unmount()`](/reference/react-dom/client/createRoot#root-unmount) instead.
51+
* `unmountComponentAtNode`: use [`root.unmount()`](/reference/react-dom/client/createRoot#root-unmount) instead.
5252
* [`renderToNodeStream`](https://18.react.dev/reference/react-dom/server/renderToNodeStream): use [`react-dom/server`](/reference/react-dom/server) APIs instead.
5353
* [`renderToStaticNodeStream`](https://18.react.dev/reference/react-dom/server/renderToStaticNodeStream): use [`react-dom/server`](/reference/react-dom/server) APIs instead.

src/content/reference/react/cache.md

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -370,7 +370,7 @@ At this time, `cache` should only be used in Server Components and the cache wil
370370

371371
#### `memo` {/*deep-dive-memo*/}
372372

373-
You should use [`memo`](reference/react/memo) to prevent a component re-rendering if its props are unchanged.
373+
You should use [`memo`](/reference/react/memo) to prevent a component re-rendering if its props are unchanged.
374374

375375
```js
376376
'use client';

src/content/reference/react/useOptimistic.md

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -51,7 +51,7 @@ function MyComponent({name, todos}) {
5151
5252
### `set` functions, like `setOptimistic(optimisticState)` {/*setoptimistic*/}
5353
54-
The `set` function returned by `useOptimistic` lets you update the state for the duration of an [Action](reference/react/useTransition#functions-called-in-starttransition-are-called-actions). You can pass the next state directly, or a function that calculates it from the previous state:
54+
The `set` function returned by `useOptimistic` lets you update the state for the duration of an [Action](/reference/react/useTransition#functions-called-in-starttransition-are-called-actions). You can pass the next state directly, or a function that calculates it from the previous state:
5555
5656
```js
5757
const [optimisticLike, setOptimisticLike] = useOptimistic(false);
@@ -68,7 +68,7 @@ function handleClick() {
6868
6969
#### Parameters {/*setoptimistic-parameters*/}
7070
71-
* `optimisticState`: The value that you want the optimistic state to be during an [Action](reference/react/useTransition#functions-called-in-starttransition-are-called-actions). If you provided a `reducer` to `useOptimistic`, this value will be passed as the second argument to your reducer. It can be a value of any type.
71+
* `optimisticState`: The value that you want the optimistic state to be during an [Action](/reference/react/useTransition#functions-called-in-starttransition-are-called-actions). If you provided a `reducer` to `useOptimistic`, this value will be passed as the second argument to your reducer. It can be a value of any type.
7272
* If you pass a function as `optimisticState`, it will be treated as an _updater function_. It must be pure, should take the pending state as its only argument, and should return the next optimistic state. React will put your updater function in a queue and re-render your component. During the next render, React will calculate the next state by applying the queued updaters to the previous state similar to [`useState` updaters](/reference/react/useState#setstate-parameters).
7373
7474
#### Returns {/*setoptimistic-returns*/}
@@ -77,7 +77,7 @@ function handleClick() {
7777
7878
#### Caveats {/*setoptimistic-caveats*/}
7979
80-
* The `set` function must be called inside an [Action](reference/react/useTransition#functions-called-in-starttransition-are-called-actions). If you call the setter outside an Action, [React will show a warning](#an-optimistic-state-update-occurred-outside-a-transition-or-action) and the optimistic state will briefly render.
80+
* The `set` function must be called inside an [Action](/reference/react/useTransition#functions-called-in-starttransition-are-called-actions). If you call the setter outside an Action, [React will show a warning](#an-optimistic-state-update-occurred-outside-a-transition-or-action) and the optimistic state will briefly render.
8181
8282
<DeepDive>
8383
@@ -161,7 +161,7 @@ function MyComponent({age, name, todos}) {
161161
`useOptimistic` returns an array with exactly two items:
162162
163163
1. The <CodeStep step={2}>optimistic state</CodeStep>, initially set to the <CodeStep step={1}>value</CodeStep> provided.
164-
2. The <CodeStep step={3}>set function</CodeStep> that lets you temporarily change the state during an [Action](reference/react/useTransition#functions-called-in-starttransition-are-called-actions).
164+
2. The <CodeStep step={3}>set function</CodeStep> that lets you temporarily change the state during an [Action](/reference/react/useTransition#functions-called-in-starttransition-are-called-actions).
165165
* If a <CodeStep step={4}>reducer</CodeStep> is provided, it will run before returning the optimistic state.
166166
167167
To use the <CodeStep step={2}>optimistic state</CodeStep>, call the `set` function inside an Action.

src/content/reference/rules/components-and-hooks-must-be-pure.md

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -70,7 +70,7 @@ function Dropdown() {
7070

7171
## Components and Hooks must be idempotent {/*components-and-hooks-must-be-idempotent*/}
7272

73-
Components must always return the same output with respect to their inputs – props, state, and context. This is known as _idempotency_. [Idempotency](https://en.wikipedia.org/wiki/Idempotence) is a term popularized in functional programming. It refers to the idea that you [always get the same result every time](learn/keeping-components-pure) you run that piece of code with the same inputs.
73+
Components must always return the same output with respect to their inputs – props, state, and context. This is known as _idempotency_. [Idempotency](https://en.wikipedia.org/wiki/Idempotence) is a term popularized in functional programming. It refers to the idea that you [always get the same result every time](/learn/keeping-components-pure) you run that piece of code with the same inputs.
7474

7575
This means that _all_ code that runs [during render](#how-does-react-run-your-code) must also be idempotent in order for this rule to hold. For example, this line of code is not idempotent (and therefore, neither is the component):
7676

@@ -132,7 +132,7 @@ Side effects are a broader term than Effects. Effects specifically refer to code
132132
Side effects are typically written inside of [event handlers](/learn/responding-to-events) or Effects. But never during render.
133133
</Note>
134134

135-
While render must be kept pure, side effects are necessary at some point in order for your app to do anything interesting, like showing something on the screen! The key point of this rule is that side effects should not run [in render](#how-does-react-run-your-code), as React can render components multiple times. In most cases, you'll use [event handlers](learn/responding-to-events) to handle side effects. Using an event handler explicitly tells React that this code doesn't need to run during render, keeping render pure. If you've exhausted all options – and only as a last resort – you can also handle side effects using `useEffect`.
135+
While render must be kept pure, side effects are necessary at some point in order for your app to do anything interesting, like showing something on the screen! The key point of this rule is that side effects should not run [in render](#how-does-react-run-your-code), as React can render components multiple times. In most cases, you'll use [event handlers](/learn/responding-to-events) to handle side effects. Using an event handler explicitly tells React that this code doesn't need to run during render, keeping render pure. If you've exhausted all options – and only as a last resort – you can also handle side effects using `useEffect`.
136136

137137
### When is it okay to have mutation? {/*mutation*/}
138138

@@ -202,7 +202,7 @@ As long as calling a component multiple times is safe and doesn’t affect the r
202202

203203
## Props and state are immutable {/*props-and-state-are-immutable*/}
204204

205-
A component's props and state are immutable [snapshots](learn/state-as-a-snapshot). Never mutate them directly. Instead, pass new props down, and use the setter function from `useState`.
205+
A component's props and state are immutable [snapshots](/learn/state-as-a-snapshot). Never mutate them directly. Instead, pass new props down, and use the setter function from `useState`.
206206

207207
You can think of the props and state values as snapshots that are updated after rendering. For this reason, you don't modify the props or state variables directly: instead you pass new props, or use the setter function provided to you to tell React that state needs to update the next time the component is rendered.
208208

0 commit comments

Comments
 (0)