Loading...
Loading...
Compare original and translation side by side
<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><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>| Pattern | Usage |
|---|---|
| Main file (no prefix) |
| Supporting files |
| Active file (reference pages) |
| Hidden files |
| CSS styles |
| External dependencies |
export default| 写法模式 | 用途 |
|---|---|
| 主文件(无前缀) |
| 辅助文件 |
| 激活文件(参考页面) |
| 隐藏文件 |
| CSS样式文件 |
| 外部依赖配置 |
export default```js {2-4}
function Example() {
// Lines 2-4
// will be
// highlighted
return null;
}```js {2-4}
function Example() {
// 第2-4行
// 将被
// 高亮显示
return null;
}```js [[1, 4, "age"], [2, 4, "setAge"]]
// Creates numbered markers pointing to "age" and "setAge" on line 4```js [[1, 4, "age"], [2, 4, "setAge"]]
// 在第4行创建指向"age"和"setAge"的编号标记```js {expectedErrors: {'react-compiler': [7]}}
// Line 7 shows as expected error```js {expectedErrors: {'react-compiler': [7]}}
// 第7行会显示为预期错误<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; }<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; }<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"
}
}<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"
}
}econst({ props })({props})econst({ props })({props})// 🚫 This will cause hydration warnings
export default function App() {
const isClient = typeof window !== 'undefined';
return <div>{isClient ? 'Client' : 'Server'}</div>;
}// 🚫 这会导致Hydration警告
export default function App() {
const isClient = typeof window !== 'undefined';
return <div>{isClient ? 'Client' : 'Server'}</div>;
}// 🚫 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; }, []);// 🚫 不要为非视觉状态触发重渲染
const [mounted, setMounted] = useState(false);
useEffect(() => { setMounted(true); }, []);
// ✅ 改用Ref
const mounted = useRef(false);
useEffect(() => { mounted.current = true; }, []);// ✅ 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) => { ... });// ✅ 命名函数可在DevTools中显示组件名称
const MyInput = forwardRef(function MyInput(props, ref) {
return <input {...props} ref={ref} />;
});
// 🚫 匿名函数会丢失组件名称
const MyInput = forwardRef((props, ref) => { ... });// ✅ Preserves component name
const Greeting = memo(function Greeting({ name }) {
return <h1>Hello, {name}</h1>;
});// ✅ 保留组件名称
const Greeting = memo(function Greeting({ name }) {
return <h1>Hello, {name}</h1>;
});| Pattern | Problem | Fix |
|---|---|---|
| Not standard | |
| Conflicts with global | |
| Re-renders | Use |
Reading | Hydration mismatch | Check in useEffect |
| Single-line if without braces | Harder to debug | Use multiline with braces |
Chained | Less clear | Two statements |
| Inconsistent | |
| Tabs | Inconsistent | 2 spaces |
| Deprecated | Use |
| Fake package names | Confusing | Use |
| Outdated | |
Missing | Warnings | Always include key |
| 模式 | 问题 | 修复方案 |
|---|---|---|
| 不符合标准 | |
| 与全局变量冲突 | |
为非渲染值使用 | 触发不必要重渲染 | 使用 |
渲染时读取 | Hydration不匹配 | 在useEffect中检查 |
| 无大括号的单行if语句 | 调试难度高 | 使用带大括号的多行写法 |
链式调用 | 可读性差 | 拆分为两个语句 |
| 格式不一致 | |
| 使用制表符 | 格式不一致 | 使用2个空格 |
| 已废弃 | 使用 |
| 虚假包名 | 易混淆 | 使用 |
| 已过时 | |
列表中缺少 | 触发警告 | 始终添加key |
// ✅ Correct
{items.map(item => <li key={item.id}>{item.name}</li>)}
// 🚫 Wrong - missing key
{items.map(item => <li>{item.name}</li>)}// ✅ 正确写法
{items.map(item => <li key={item.id}>{item.name}</li>)}
// 🚫 错误写法 - 缺少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';// ✅ 正确写法 - 路径具有描述性
import { fetchData } from './your-data-layer';
// 🚫 错误写法 - 看起来像真实的npm包
import { fetchData } from 'cool-data-lib';// ✅ Correct - labeled for clarity
console.log('User:', user);
console.log('Component Stack:', errorInfo.componentStack);
// 🚫 Wrong - unlabeled
console.log(user);// ✅ 正确写法 - 添加标签提升可读性
console.log('User:', user);
console.log('Component Stack:', errorInfo.componentStack);
// 🚫 错误写法 - 无标签
console.log(user);// ✅ Correct - 1-1.5 seconds
setTimeout(() => setLoading(false), 1000);
// 🚫 Wrong - too long, feels sluggish
setTimeout(() => setLoading(false), 3000);// ✅ 正确写法 - 1-1.5秒
setTimeout(() => setLoading(false), 1000);
// 🚫 错误写法 - 时间过长,体验卡顿
setTimeout(() => setLoading(false), 3000);{2-4}{2-4}Gallery.jsgallery.jssrc/Gallery.jssrc/Gallery.jsGallery.jsgallery.jssrc/Gallery.jssrc/Gallery.jsProfileAvatarTodoListPackingListconst [count, setCount] = useState(0)[isOnline, setIsOnline][isPacked, setIsPacked]'typing''submitting''success''error'handleClickhandleSubmithandleAddTaskonClickonChangeonAddTaskonSelectuseOnlineStatususeChatRoomuseFormInput'added''changed''deleted''changed_selection''sent_message'setCount(n => n + 1)ProfileAvatarTodoListPackingListconst [count, setCount] = useState(0)[isOnline, setIsOnline][isPacked, setIsPacked]'typing''submitting''success''error'handleClickhandleSubmithandleAddTaskonClickonChangeonAddTaskonSelectuseOnlineStatususeChatRoomuseFormInput'added''changed''deleted''changed_selection''sent_message'setCount(n => n + 1)// 🔴 Avoid: redundant state and unnecessary Effect
// ✅ Good: calculated during renderingconsole.log('✅ Connecting...');
console.log('❌ Disconnected.');// 🔴 避免:冗余状态和不必要的Effect
// ✅ 推荐:在渲染时计算console.log('✅ 连接中...');
console.log('❌ 已断开连接。');// 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);
}// 服务端组件
async function Notes() {
const notes = await db.notes.getAll();
}
// 客户端组件
"use client"
export default function Expandable({children}) {
const [expanded, setExpanded] = useState(false);
}import marked from 'marked'; // 35.9K (11.2K gzipped)
import sanitizeHtml from 'sanitize-html'; // 206K (63.3K gzipped)import marked from 'marked'; // 35.9K(压缩后11.2K)
import sanitizeHtml from 'sanitize-html'; // 206K(压缩后63.3K)react: betareact: 19.0.0-rc-*```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)react: betareact: 19.0.0-rc-*```json package.json hidden
{
"dependencies": {
"react": "latest",
"react-dom": "latest",
"react-scripts": "latest",
"immer": "1.7.3"
}
}
**版本约定:**
- 稳定特性使用`"latest"`
- 仅在兼容性要求时使用精确版本
- 仅包含示例所需的最小依赖| File Type | Reason |
|---|---|
| Configuration not the teaching point |
| Sandbox setup is boilerplate |
| HTML structure not the focus |
| When it contains sample/mock data |
| When showing API usage, not implementation |
| When styling is not the lesson |
| Supporting infrastructure |
| Server action implementation details |
```js src/data.js hidden
export const items = [
{ id: 1, name: 'Item 1' },
{ id: 2, name: 'Item 2' },
];undefined| 文件类型 | 原因 |
|---|---|
| 配置信息非教学重点 |
| Sandbox配置为样板代码 |
| HTML结构非关注重点 |
| 包含示例/模拟数据时 |
| 展示API用法而非实现时 |
| 样式非教学内容时 |
| 辅助基础设施代码 |
| 服务端动作实现细节 |
```js src/data.js hidden
export const items = [
{ id: 1, name: 'Item 1' },
{ id: 2, name: 'Item 2' },
];undefinedactivesrc/index.jssrc/App.js```js src/App.js active
// This file will be focused when example loads
export default function App() {
// ...
}undefinedactivesrc/index.jssrc/App.js```js src/App.js active
// 示例加载时将聚焦此文件
export default function App() {
// ...
}undefined| 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 |
App.jsGallery.jsButton.jsdata.jsutils.jsTasksContext.js| 场景 | 结构 | 原因 |
|---|---|---|
| 基础Hook用法 | 单文件 | 简洁、聚焦 |
| 教学导入语法 | 2-3个文件 | 展示模块化特性 |
| Context模式 | 4-5个文件 | 贴近真实项目结构 |
| 复杂状态管理 | 3个以上文件 | 关注点分离 |
App.jsGallery.jsButton.jsdata.jsutils.jsTasksContext.js.panel.button-primary.panel-dark.panel.button-primary.panel-dark