mcpField
D
docs-sandpack

docs-sandpack

github.com/reactjs开发11.8k83 次安装1 天前更新
代码仓库

关于 docs-sandpack

docs-sandpack 是一项用于编写 React Sandpack 示例的文档技能,面向文档作者。它涵盖文件结构、代码风格、行标记和示例依赖配置。

主要功能

  1. 01单文件与多文件示例模式
  2. 02文件命名及可见性规范
  3. 03代码行高亮与标注
  4. 04React 示例风格要求
  5. 05依赖与 package.json 指引

适用场景

  1. 01编写文档中的 React 示例
  2. 02组织跨多个文件的示例
  3. 03标记代码行与预期错误
  4. 04检查 Sandpack 示例风格

安装

复制下面的命令,在终端中运行。

$npx skills add https://github.com/reactjs/react.dev --skill docs-sandpack

安装后在 Claude Code 中输入/docs-sandpack确认已加载。

详细介绍

Sandpack 模式

快速入门模板

大多数示例都是单文件的。复制此模板并进行修改:

<Sandpack>

` ` `js
import { useState } from 'react';

export default function Example() {
  const [value, setValue] = useState(0);

  return (
    <button onClick={() => setValue(value + 1)}>
      Clicked {value} times
    </button>
  );
}
` ` `

</Sandpack>

文件命名

模式用途
```js主文件(无前缀)
```js src/FileName.js辅助文件
```js src/File.js active活动文件(参考页面)
```js src/data.js hidden隐藏文件
```cssCSS 样式
```json package.json外部依赖

重要: 主文件必须包含 export default。

行高亮

```js {2-4}
function Example() {
  // Lines 2-4
  // will be
  // highlighted
  return null;
}

代码引用(带编号的标注)

```js [[1, 4, "age"], [2, 4, "setAge"]]
// Creates numbered markers pointing to "age" and "setAge" on line 4

预期错误(有意写错的示例)

```js {expectedErrors: {'react-compiler': [7]}}
// Line 7 shows as expected error

多文件示例

<Sandpack>

```js src/App.js
import Gallery from './Gallery.js';

export default function App() {
  return <Gallery />;
}
export default function Gallery() {
  return <h1>Gallery</h1>;
}
h1 { color: purple; }
```

External Dependencies

<Sandpack>

```js
import { useImmer } from 'use-immer';
// ...
{
  "dependencies": {
    "immer": "1.7.3",
    "use-immer": "0.5.1",
    "react": "latest",
    "react-dom": "latest",
    "react-scripts": "latest"
  }
}
```

Code Style in Sandpack (Required)

Sandpack examples are held to strict code style standards:

  1. Function declarations for components (not arrows)
  2. e for event parameters
  3. Single quotes in JSX
  4. const unless reassignment needed
  5. Spaces in destructuring: ({ props }) not ({props})
  6. Two-line createRoot: separate declaration and render call
  7. Multiline if statements: always use braces
Don't Create Hydration Mismatches

Sandpack examples must produce the same output on server and client:

// 🚫 This will cause hydration warnings
export default function App() {
  const isClient = typeof window !== 'undefined';
  return <div>{isClient ? 'Client' : 'Server'}</div>;
}
使用 Ref 保存不参与渲染的状态
// 🚫 Don't trigger re-renders for non-visual state
const [mounted, setMounted] = useState(false);
useEffect(() => { setMounted(true); }, []);

// ✅ Use ref instead
const mounted = useRef(false);
useEffect(() => { mounted.current = true; }, []);

forwardRef 和 memo 模式

forwardRef - 使用具名函数
// ✅ Named function for DevTools display name
const MyInput = forwardRef(function MyInput(props, ref) {
  return <input {...props} ref={ref} />;
});

// 🚫 Anonymous loses name
const MyInput = forwardRef((props, ref) => { ... });
memo - 使用具名函数
// ✅ Preserves component name
const Greeting = memo(function Greeting({ name }) {
  return <h1>Hello, {name}</h1>;
});

行长度

  • 正文:约 80 个字符
  • 代码:约 60–70 个字符
  • 拆分过长的行,避免水平滚动

反模式

模式问题修正方法
const Comp = () => {}不符合惯例function Comp() {}
onClick={(event) => ...}与全局变量冲突onClick={(e) => ...}
用 useState 保存不参与渲染的值会重新渲染使用 useRef
渲染期间读取 window水合不匹配在 useEffect 中检查
不带花括号的单行 if更难调试使用带花括号的多行写法
链式调用 createRoot().render()不够清晰拆成两条语句
//... 后没有空格格式不一致使用带空格的 // ...
制表符格式不一致使用 2 个空格
ReactDOM.render已弃用使用 createRoot
虚构的包名容易造成混淆使用 './your-storage-layer'
PropsWithChildren已过时使用 children?: ReactNode
列表中缺少 key会产生警告始终包含 key

其他代码质量规则

列表项始终包含 Key
// ✅ Correct
{items.map(item => <li key={item.id}>{item.name}</li>)}

// 🚫 Wrong - missing key
{items.map(item => <li>{item.name}</li>)}
使用真实的导入路径
// ✅ Correct - descriptive path
import { fetchData } from './your-data-layer';

// 🚫 Wrong - looks like a real npm package
import { fetchData } from 'cool-data-lib';
Console.log 标签
// ✅ Correct - labeled for clarity
console.log('User:', user);
console.log('Component Stack:', errorInfo.componentStack);

// 🚫 Wrong - unlabeled
console.log(user);
延迟时间应合理
// ✅ Correct - 1-1.5 seconds
setTimeout(() => setLoading(false), 1000);

// 🚫 Wrong - too long, feels sluggish
setTimeout(() => setLoading(false), 3000);

更新行高亮

修改带有行高亮({2-4})的示例代码时,务必更新高亮行号,使其与新代码一致。行号错误会导致渲染崩溃。

文件名约定

  • 组件文件的文件名首字母大写:使用 Gallery.js,而不是 gallery.js
  • 初次说明文件位于 src/ 后,只用文件名指代文件:使用 Gallery.js,而不是 src/Gallery.js

代码命名约定

组件: PascalCase

  • Profile、Avatar、TodoList、PackingList

状态变量: 使用解构模式

  • const [count, setCount] = useState(0)
  • 布尔值:[isOnline, setIsOnline]、[isPacked, setIsPacked]
  • 状态字符串:'typing'、'submitting'、'success'、'error'

事件处理函数:

  • handleClick、handleSubmit、handleAddTask

回调属性:

  • onClick、onChange、onAddTask、onSelect

自定义 Hooks:

  • useOnlineStatus、useChatRoom、useFormInput

Reducer 操作:

  • 使用过去时:'added'、'changed'、'deleted'
  • 复合名称使用蛇形命名法:'changed_selection'、'sent_message'

更新函数: 使用单个字母

  • setCount(n => n + 1)
教学用代码标记

错误代码与正确代码:

// 🔴 Avoid: redundant state and unnecessary Effect
// ✅ Good: calculated during rendering

用于讲解生命周期的 Console.log:

console.log('✅ Connecting...');
console.log('❌ Disconnected.');
服务端/客户端标注
// Server Component
async function Notes() {
  const notes = await db.notes.getAll();
}

// Client Component
"use client"
export default function Expandable({children}) {
  const [expanded, setExpanded] = useState(false);
}
Bundle 大小注释
import marked from 'marked'; // 35.9K (11.2K gzipped)
import sanitizeHtml from 'sanitize-html'; // 206K (63.3K gzipped)

Sandpack 示例指南

Package.json 规则

以下情况应包含 package.json:

  • 使用外部 npm 包(immer、remarkable、leaflet、toastify-js 等)
  • 演示实验性或 canary 版 React 功能
  • 需要指定 React 版本(react: beta、react: 19.0.0-rc-*)

以下情况不应包含 package.json:

  • 示例仅使用 React 内置功能
  • 无需外部依赖
  • 讲解基础 Hooks、状态或组件

始终将 package.json 标记为隐藏文件:

```json package.json hidden
{
  "dependencies": {
    "react": "latest",
    "react-dom": "latest",
    "react-scripts": "latest",
    "immer": "1.7.3"
  }
}

**Version conventions:**
- Use `"latest"` for stable features
- Use exact versions only when compatibility requires it
- Include minimal dependencies (just what the example needs)

### Hidden File Patterns

**Always hide these file types:**

| File Type | Reason |
|-----------|--------|
| `package.json` | Configuration not the teaching point |
| `sandbox.config.json` | Sandbox setup is boilerplate |
| `public/index.html` | HTML structure not the focus |
| `src/data.js` | When it contains sample/mock data |
| `src/api.js` | When showing API usage, not implementation |
| `src/styles.css` | When styling is not the lesson |
| `src/router.js` | Supporting infrastructure |
| `src/actions.js` | Server action implementation details |

**Rationale:**
- Reduces cognitive load
- Keeps focus on the primary concept
- Creates cleaner, more focused examples

**Example:**
```mdx
```js src/data.js hidden
export const items = [
  { id: 1, name: 'Item 1' },
  { id: 2, name: 'Item 2' },
];

### Active File Patterns

**Mark as active when:**
- File contains the primary teaching concept
- Learner should focus on this code first
- Component demonstrates the hook/pattern being taught

**Effect of the `active` marker:**
- Sets initial editor tab focus when Sandpack loads
- Signals "this is what you should study"
- Works with hidden files to create focused examples

**Most common active file:** `src/index.js` or `src/App.js`

**Example:**
```mdx
```js src/App.js active
// This file will be focused when example loads
export default function App() {
  // ...
}

### File Structure Guidelines

| Scenario | Structure | Reason |
|----------|-----------|--------|
| Basic hook usage | Single file | Simple, focused |
| Teaching imports | 2-3 files | Shows modularity |
| Context patterns | 4-5 files | Realistic structure |
| Complex state | 3+ files | Separation of concerns |

**Single File Examples (70% of cases):**
- Use for simple concepts
- 50-200 lines typical
- Best for: Counter, text inputs, basic hooks

**Multi-File Examples (30% of cases):**
- Use when teaching modularity/imports
- Use for context patterns (4-5 files)
- Use when component is reused

**File Naming:**
- Main component: `App.js` (capitalized)
- Component files: `Gallery.js`, `Button.js` (capitalized)
- Data files: `data.js` (lowercase)
- Utility files: `utils.js` (lowercase)
- Context files: `TasksContext.js` (named after what they provide)

### Code Size Limits

- Single file: **<200 lines**
- Multi-file total: **150-300 lines**
- Main component: **100-150 lines**
- Supporting files: **20-40 lines each**

### CSS Guidelines

**Always:**
- Include minimal CSS for demo interactivity
- Use semantic class names (`.panel`, `.button-primary`, `.panel-dark`)
- Support light/dark themes when showing UI concepts
- Keep CSS visible (never hidden)

**Size Guidelines:**
- Minimal (5-10 lines): Basic button styling, spacing
- Medium (15-30 lines): Panel styling, form layouts
- Complex (40+ lines): Only for layout-focused examples

评论

支持 Markdown