className={undefined} leaves an empty class="" attribute after client rendering, so [class] selectors match
维护者通常 1 天内回复
还没有人认领这个 Issue。
评估
- 难度
- 2/5
- 预计耗时
- 1-3 小时
- 新手友好度
- 84/100
- Issue 类型
- 缺陷
- 描述清晰度
- 描述清楚
- 活跃度
- 活跃
- 技术栈
- next.js, react, typescript
- 领域
- frontend
调研方向
从 packages/redact/src/dom/dom.ts 中 issue 所示的 className 赋值处开始,然后运行提供的 Next.js 复现示例,并在浏览器控制台中检查 class 属性。当 className 为 null 或 undefined 时不留下 class 属性,而空字符串 className 仍会生成 class="",与 React 一致,即为完成。
由索引模型根据 Issue 内容生成。
描述
Version: @tanstack/redact 0.2.6 through withRedact, Next.js 16.4.4 (App Router, Turbopack), react/react-dom 19.3.1, Chrome 156, production build. dom.ts is unchanged on main (049de24f).
What happens
When an HTML element is created or updated in the browser with className={undefined}, Redact leaves an empty class="" attribute. React leaves no attribute at all.
The cause is in packages/redact/src/dom/dom.ts:
(el as HTMLElement).className = next == null ? '' : '' + next;
Assigning an empty string to className creates the attribute.
| Element | React 19.3.1 | Redact 0.2.6 |
|---|---|---|
className={undefined}, server-rendered and hydrated |
no attribute | no attribute |
className={undefined}, server-rendered, then re-rendered |
no attribute | no attribute |
className={undefined}, rendered only in the browser |
no attribute | class="" |
className changes from 'x' to undefined |
no attribute | class="" |
className="" |
class="" |
class="" |
Why it matters
Selectors that test whether the attribute exists, such as section[class] or :not([class]), now match differently. CSS Modules make this easy to hit, because styles.name is undefined when a class has no rules.
We found it by comparing screenshots of our app against React baselines. An A/A run of React against itself was clean. A global section[class] rule started to apply to one section, which gained 70 px of block padding and a background, and the page grew 140 px taller. Removing the empty attribute in the browser restored the React layout exactly.
Together with #85 and #81, this keeps us from using Redact in production on Next.js.
Reproduction
package.json dependencies: [email protected], [email protected], [email protected], @tanstack/[email protected].
next.config.mjs:
import { withRedact } from '@tanstack/redact/next'
export default withRedact({})
app/layout.js:
export default function RootLayout({ children }) {
return (
<html lang="en">
<body>{children}</body>
</html>
)
}
app/page.js:
'use client'
import { useEffect, useState } from 'react'
export default function Page() {
const [mounted, setMounted] = useState(false)
useEffect(() => setMounted(true), [])
return (
<main>
<section id="ssr-undefined" className={undefined}>a</section>
<section id="ssr-empty" className="">b</section>
<section id="rerender-undefined" className={undefined} data-n={mounted ? 1 : 0}>c</section>
<section id="toggle-to-undefined" className={mounted ? undefined : 'x'}>d</section>
{mounted ? <section id="client-undefined" className={undefined}>e</section> : null}
{mounted ? <section id="client-empty" className="">f</section> : null}
</main>
)
}
Run next build && next start, open /, and run this in the console:
Object.fromEntries([...document.querySelectorAll('section')].map((e) => [e.id, e.getAttribute('class')]))
Redact 0.2.6:
{"ssr-undefined":null,"ssr-empty":"","rerender-undefined":null,"toggle-to-undefined":"","client-undefined":"","client-empty":""}
React 19.3.1:
{"ssr-undefined":null,"ssr-empty":"","rerender-undefined":null,"toggle-to-undefined":null,"client-undefined":null,"client-empty":""}
Expected
The same result as React: a null or undefined className leaves no class attribute.
Suggested fix
if (next == null) el.removeAttribute('class');
else (el as HTMLElement).className = '' + next;
- 主要语言
- TypeScript
- 星标
- 537
- 派生
- 22
- 平均合并
- 11 小时 28 分钟
- 30 天内合并 PR
- 34
环境准备
这个项目没有提供开发容器、Dockerfile 或贡献指南,环境需要你自己搭建:先看它的 README,通用步骤见我们的新手贡献指南。
从这里开始
- 先读完整个 Issue,再读项目的贡献指南。
- 在 Issue 下留言说明你要接手 —— 这能避免两个人做同样的事。
- Fork 仓库,在一个分支上完成修改。
- 提交 Pull Request,并在描述里引用这个 Issue 编号。
TanStack/redact 的其他 Issue
-
难度 2/5 1-3 小时 新手友好度 85/100
维护者通常 1 天内回复
-
难度 2/5 1-3 小时 新手友好度 78/100
维护者通常 1 天内回复
-
难度 4/5 3-5 天 新手友好度 55/100
维护者通常 1 天内回复
-
难度 3/5 1-2 天 新手友好度 48/100
维护者通常 1 天内回复
-
难度 3/5 1-2 天 新手友好度 68/100
维护者通常 1 天内回复
相似的 Issue
-
Add: Yichang TV未关闭check:passed streams:add
难度 2/5 1-3 小时 新手友好度 74/100
维护者通常 1 天内回复
-
vtselect: data race in Tempo search tags APIs for invalid TraceQL queries可能已有人在做 @Shubham19032004 今天认领。 未关闭bug
难度 2/5 1-3 小时 新手友好度 78/100
VictoriaMetrics/VictoriaTraces#304 ·
维护者通常 1 天内回复
-
test: claim-conflict drop leaves both facts active and is never re-proposed (untested review cell)未关闭
难度 2/5 1-3 小时 新手友好度 83/100
维护者通常 1 天内回复
-
难度 2/5 1-3 小时 新手友好度 78/100
microsoft/vscode-pull-request-github#9159 ·
维护者通常 1 天内回复
-
[Feature]: Usage page should show API-equivalent cost and say when a connected plan shows info only未关闭enhancement from-x
难度 2/5 1-3 小时 新手友好度 66/100
nightly-labs/openbot#4867 ·
维护者通常 1 天内回复