一句话先修(最快路径): 预览空白几乎都意味着 React 代码抛了错、而沙箱把错误横幅吞掉了。打开浏览器 DevTools(F12)-> Console 标签 -> 勾上 “Preserve log” -> 再点一次 Preview,读出真正的异常(通常是 TypeError: Cannot read properties of undefined (reading 'map'))。如果预览上出现 Try fixing with Claude 按钮,先点它。如果整个面板在代码运行前就一片空白,那多半是浏览器扩展或广告拦截器挡住了沙箱 iframe —— 用无痕窗口重试一下。
你让 Claude 写一个小的 React 组件 artifact —— 一个图表、一个表单、一组卡片。代码看上去没毛病,点 Preview,预览面板里一片空白。没有 loading,没有报错横幅,没有红色堆栈,什么都没有。滚动、改尺寸、点刷新,依然空白。切回 Code 视图,JSX 看着挺正常。你问 Claude “为什么空白?“,Claude 自信满满地把组件改写成一个略微不同的版本,继续空白。这种情况几乎都是沙箱吞掉了运行时报错 —— prop 类型不匹配、import 拿不到、没有 default export,或者 hydration 直接崩了,但沙箱接住后什么都不显示。
你属于哪一类?
在读任何代码之前,这个两步分诊能帮你直接定位到对应原因:
| 你看到的现象 | 最可能的类别 | 跳到 |
|---|---|---|
| 代码还没运行就空白,而且每个 artifact(连最小模板都)空白 | 浏览器扩展 / 广告拦截器挡住了沙箱 iframe | 原因 7,再看第 5 步 |
| 只有这一个 artifact 空白,其它都正常 | 生成代码里的运行时错误(prop / export / import / hook) | 原因 1-5,第 1 步 |
| 组件确实在 DOM 里,但视觉上是空的 | 零尺寸 CSS,不是崩溃 | 原因 6,第 6 步 |
| 本来好的,Claude 帮你”保存”数据之后变空白了 | 沙箱屏蔽了 localStorage / sessionStorage | 原因 8 |
最快的一招还是第 1 步:点 Preview 之前先开 DevTools 控制台。有真实异常 = 代码类问题;控制台一片安静、面板却空白 = iframe / 扩展类问题。
常见原因
按真实 artifact 调试中观察到的频率排序。
1. 组件期望一个 prop,但 artifact 宿主并没传
Claude 写了 export default function Card({ title, items }) { ... },但调用时只写了 <Card />,没传 props。一到 items.map(...) 就在 undefined 上炸。沙箱接住,渲染成空。
如何识别:打开 Code 视图。找一下所有 props.something.map、props.something.length、或者解构出来的 prop。如果父级调用没传那些,就是这个原因。
2. 缺 default export,或 named export 命名错
artifact 宿主导入的是顶层的 default export。如果 Claude 写的是 export function Component()、没有 default,宿主拿到的是 undefined,啥都不渲染。同理还有拼写错的 export defalut function。
如何识别:在代码里搜索 export default,应该刚好有一处。如果只有 export function、没有任何 export default,就是它。
3. import 引了 artifact 运行时不支持的包
Claude 写了 import { LineChart } from 'recharts',但你账号 / 区域下的 artifact 运行时没把 recharts 加白名单。import 结果是 undefined,组件构造失败,沙箱渲染空白。
如何识别:看所有 import 行。截至 2026 年 6 月,artifact 运行时的白名单是固定的一小撮:react / react-dom(含 hooks)、lucide-react(锁定在 0.263.1,这版之后新增的图标名解析不出来)、recharts、d3、three(锁定在 r128,所以 OrbitControls 等后来的附加模块会失败)、mathjs、lodash、papaparse、xlsx,以及 shadcn/ui 原语。没有任意 npm install,任何 CDN 托管的库(Chart.js、Google Fonts 等)都会被沙箱 CSP 静默拦掉。不在这个名单里的都得怀疑 —— 让 Claude 换成白名单里的库,或者直接 inline 实现。
4. JSX 语法错误被解析器吞了
Claude 生成的 JSX 里混入了一个游离的 < 或 >。构建阶段解析失败,失败信息有时不在预览面板里高亮显示。
如何识别:找有没有非花括号包裹的 JSX 表达式,但里面又含 < 或 >,比如写成了 <p>1 < 2</p> 而不是 <p>{'1 < 2'}</p>。
5. hook 写在条件分支或 early return 之后
React 的 hooks 规则。如果 Claude 写了 if (!data) return null;,然后下面才 const [state, setState] = useState(...),下一次渲染时 hook 数量对不上,直接抛错。在 artifact 沙箱里这个抛错是静默的。
如何识别:从函数体顶部往下顺一遍。每个 useState、useEffect、useMemo 在所有渲染路径上都要执行。任何一个被条件包裹,就是 bug。
6. Tailwind class 拼错,组件渲染出零尺寸
Claude 写了 class="w-0 h-0 ...",或者用了根本不存在的 Tailwind 工具类(比如 text-9.5xl),结果整个容器塌缩到 0。组件其实渲染了,只是看不见。
如何识别:在预览 iframe 上打开浏览器 DevTools(右键 → 检查元素)。如果 DOM 里有你的组件,但 width: 0 / height: 0,就是这个。
7. 浏览器扩展或广告拦截器挡住了沙箱 iframe
当每个 artifact(连最简单的也)都空白时,这是最常见的原因。artifact 渲染在一个沙箱 iframe 里,而且来自独立的域(artifact 宿主 claudeusercontent.com)。广告拦截器、脚本拦截器、严格的隐私扩展(uBlock Origin、Privacy Badger、Brave Shields,以及一些公司 VPN/代理过滤)会把这个跨域 frame 拦掉,于是什么都加载不出来,控制台甚至可能一片安静。
如何识别:用无痕 / 隐私窗口打开 Claude(扩展默认关闭)。如果那里能正常渲染,就是扩展的锅 —— 一个个重新启用扩展找出是哪个,或者把 claude.ai 和 claudeusercontent.com 加白名单。
8. 组件用了 localStorage 或 sessionStorage
artifact 沙箱屏蔽了浏览器存储 API。像 localStorage.getItem(...) 或 localStorage.setItem(...) 这种代码一运行就抛 SecurityError(或者静默失效),然后被沙箱吞掉。典型表现是:“本来好的,我让 Claude 记住 / 持久化某个东西之后就空白了。”
如何识别:在 artifact 代码里搜 localStorage、sessionStorage、indexedDB、document.cookie。artifact 里出现任何一个都是红灯。让 Claude 把持久化改成 React state(useState / useReducer)、useRef 或内存变量。
排查前的准备
- 把空白预览面板和 Code 视图并排截图。
- 记一下当前这次对话里,artifact 有没有曾经正确渲染过哪怕一次 —— 如果有,说明是后来某一轮被 Claude 改坏的。
- 确认你用的是 Web 版 Claude 还是某个桌面壳子。桌面端的沙箱 CSP 有时比 Web 严。
需要收集的信息
- artifact 的完整代码(从 Code 视图复制粘贴)。
- 当前使用的 Claude 模型(Sonnet 4.6、Opus 4.7 等)。
- 点 Preview 那一刻可能短暂闪过的错误文字(往往不到 1 秒就消失)。
- artifact 顶部的所有 import 列表。
- 你的账号套餐 —— 免费版的 artifact 库白名单更小。
- 浏览器 DevTools 控制台输出(在点 Preview 之前就先打开)。
一步步修复
按 ROI 排序,便宜的检查在前。
第 1 步:读出真正的报错 —— 先看控制台,或用内置按钮
这一步最关键。把被吞掉的异常暴露出来有两个办法:
1. 在 Claude 页面任意位置右键 → 检查(或按 F12)。
2. 打开 Console 标签。
3. 勾上"保留日志"(Preserve log),防止报错被清掉。
4. 现在再点 artifact 的 Preview。
artifact 的 iframe 是沙箱,但报错确实会冒泡到父页面的控制台。你能看到真实的异常信息,通常是 TypeError: Cannot read properties of undefined (reading 'map') 或 ReferenceError: SomePackage is not defined,直接告诉你要修哪。
截至 2026 年 6 月,artifact 在运行时抛错时,Claude 还会在预览上给出一个 Try fixing with Claude 按钮。点它:Claude 会带着真实堆栈重读 artifact,一轮就把它修好。这比在对话里描述症状快 —— 因为 Claude 本来看不到 iframe 里的东西,只能瞎猜。
第 2 步:让 Claude 套一个防御性包装层
一句 prompt 能修掉大多数 prop 相关的空白:
artifact 预览空白,且没有可见错误。请用 try/catch ErrorBoundary
把组件包起来,把捕获到的错误信息直接渲染到 UI 上。另外,给每一个
组件解构出的 prop 加上默认值。
Claude 会改写成 const { title = 'Untitled', items = [] } = props,再加上一个把错误显示出来的 ErrorBoundary。
第 3 步:强制只保留一个 default export
让 Claude:
重构组件,在文件末尾保留唯一一个 default export:
export default ComponentName。删除其它所有 export。确认顶层
调用的标签名跟它对得上。
一句话搞定原因 #2。
第 4 步:把奇怪的 import 换成白名单内的
如果 import 列表里出现了 react / recharts / lucide-react / shadcn 之外的东西:
请只用以下库重写:react、recharts、lucide-react。如果需要一个
不在里面的 UI 原语,用 Tailwind 直接 inline 实现。
这能消掉原因 #3。
第 5 步:用一个已知能跑的最小模板兜底
把 artifact 重置到一个已知能跑的起点:
import React, { useState } from 'react';
export default function App() {
const [count, setCount] = useState(0);
return (
<div className="p-6">
<h1 className="text-2xl font-bold">Hello</h1>
<button onClick={() => setCount(count + 1)}>{count}</button>
</div>
);
}
如果这个能跑,沙箱本身没问题,问题在 Claude 生成的代码。如果连这个最小模板都空白,那问题出在环境,不在代码:
1. 强制刷新页面:Cmd+Shift+R(Mac)/ Ctrl+Shift+R(Windows)。
2. 用无痕 / 隐私窗口打开 Claude 再试。
如果那里能渲染,说明某个浏览器扩展挡住了沙箱 iframe
(原因 7)—— 把 claude.ai 和 claudeusercontent.com 加白名单,
或关掉广告 / 脚本拦截器。
3. 对比一下 Claude 桌面 App 和 Web 版,定位是不是浏览器
特有的 CSP 差异。
如果在干净的无痕窗口里(没有扩展)最小模板还是空白,那是沙箱本身坏了 —— 提工单。也可参考 Claude artifact 渲染空白。
第 6 步:检查 DOM 里有没有零尺寸的元素
如果 DevTools 里能看到你的组件确实在 DOM 中,但预览视觉上空白:
1. DevTools → Elements 标签。
2. 找到你的顶层组件 div。
3. 看 Computed → width / height。
4. 如果是 0px,说明父容器塌缩了。要么显式加 minHeight,
要么去掉冲突的 Tailwind class。
这能抓到原因 #6。
验证
- 修完之后,在 DevTools 控制台打开的状态下再点一次 Preview。
- 控制台不应有红色报错(key 相关的 warning 没关系)。
- Elements 面板里组件可见,尺寸非 0。
- 跟组件交互一下(点击、输入),操作不应该再触发新的错误。
长期预防
- 给 Claude 生成的所有 prop 都加默认值:
{ title = '', items = [] }。 - 让 Claude 默认在每个 artifact 外面套一个 ErrorBoundary,把捕获到的错误显式渲染出来。
- 留一份”已知能跑的最小模板”片段,从它开始迭代,比直接从复杂需求生成更稳。
- 在 prompt 里钉死 artifact 依赖:“只用 react、recharts、lucide-react,别引其他库。”
- 永远别让 artifact 用
localStorage/sessionStorage做持久化 —— 沙箱会屏蔽。直接说”所有状态都放 React state 里,别用浏览器存储”。 - 让 Claude 在现有 artifact 上迭代时,把当前代码贴回去 —— 否则它会从零重写,丢掉上下文。
常见坑
- 把”预览空白”理解成”还没生成代码” —— 其实通常是”代码抛了,但没出现在 UI 上”。永远先看控制台。
- 直接问 Claude “为什么空白”而不给它控制台报错 —— Claude 看不到 iframe 控制台,只能瞎猜。
- 在一个坏掉的 artifact 上迭代 10 次。失败超过 3 次,就重置成最小模板,一步步往上加。
- 以为在 Sonnet 上能跑的组件在 Opus 上一模一样能跑 —— 两个模型各自假定可用的库会有微妙差异。
- 在 artifact 里用
dangerouslySetInnerHTML—— 沙箱有时会剥掉它,组件看着就是空。 - 让 Claude 用
localStorage“保存”或”记住”数据 —— 沙箱屏蔽浏览器存储,组件会抛错变空白(原因 8)。改用 React state。
FAQ
Q:控制台显示 “ChunkLoadError”,怎么办?
artifact 运行时想 lazy-load 一个 chunk 但失败了(网络或 CSP)。先强制刷新 Claude 页面(Cmd+Shift+R / Ctrl+Shift+R)。如果还是,说明你的 import 里某个库会触发被沙箱拦截的动态 import。换成白名单里可静态引入的替代品(react、recharts、lucide-react、d3、three、lodash、mathjs)。
Q:控制台报了个跟 localStorage 有关的 SecurityError,为什么?
artifact 沙箱屏蔽了 localStorage、sessionStorage、indexedDB、document.cookie。任何持久化调用都会抛错,组件渲染成空。让 Claude 把状态放在 useState / useReducer(内存里)就行。如果你确实需要持久化,把 artifact 导出到你自己的 React 项目里,那些 API 在那边可用。
Q:每个 artifact 都空白,连简单的也空白 —— Claude 挂了吗?
通常不是。每个 artifact(包括上面那个最小模板)都空白,指向的是浏览器扩展或广告拦截器挡住了沙箱 iframe,而不是 Claude 本身。用无痕窗口测一下;如果那里能跑,把 claude.ai 和 claudeusercontent.com 加白名单。只有当无痕窗口里也空白时,才需要去看 Anthropic 状态页。
Q:同样的代码在 Claude 里能跑,我复制到自己的 React 项目就空白,为啥?
artifact 运行时自动注入了 React、有时候是 Tailwind,以及 shadcn 原语的 shim。你自己的项目得手动装并配上:npm install react react-dom recharts lucide-react,Tailwind 也要先配好。
Q:能看到 artifact 沙箱实际接住的错误文本吗?
可以 —— 在父页面的 DevTools 控制台里(见第 1 步)。沙箱吞掉了视觉上的错误横幅,但错误本身会冒泡到父窗口的 console。
Q:同一段 prompt,作者的 Claude 能跑,我的空白,为什么?
很可能是模型或套餐差异。免费版的 artifact 运行时白名单更紧。Pro / Team 版能 import 更多库。如果教程里能跑,先看下作者用的什么套餐。
相关阅读
- Claude artifact 渲染空白
- Claude artifact 编辑后丢失改动
- Claude artifact 下载问题
- Claude 回答不准确
- Claude 工具调用一直 pending
标签: #排查 #Claude #artifacts #react #调试