在本地没问题(已知警告并且 CSS 渲染良好),但在 Vercel 上我的 Remix 应用程序收到此错误:
水合失败,因为初始 UI 与原来的 UI 不匹配
在服务器上渲染。
业务逻辑运行良好,但 CSS 完全损坏。
2022 年 6 月 26 日 15:50 更新
我从头开始了一个新项目,并逐一添加依赖项,并在每一步中部署到 Vercel。没有错误。样式化的组件渲染良好。所以依赖关系不是问题。
然后,我开始通过加载器从数据库中逐段获取数据,并将它们一一呈现在样式组件中。始终破坏 CSS 并产生错误的一件事是在渲染之前将日期时间对象转换为字符串:
const DateTimeSpan = styled.span`
font-size: 1rem;
`;
const hr = now.getHours();
const min = now.getMinutes();
<DateTimeSpan>
{`${hr}:${min}`}
</DateTimeSpan>
奇怪的是,只有当我将其格式化为仅渲染时间时,它才会中断。有了日期,就可以了:
const yr = now.getFullYear();
const mth = now.getMonth();
const dd = now.getDate();
<DateTimeSpan>
{`${yr}-${mth}-${dd}`}
<DateTimeSpan>
我无法解释这一点。
更新于 2022 年 7 月 2 日 21:55
使用上面相同的最简单的项目,我和朋友确定当我们尝试渲染时带有样式组件的 CSS 会中断hours, i.e.:
const hr = now.getHours();
<DateTimeSpan>
{hr}
</DateTimeSpan>
我们怀疑样式组件会损坏,因为小时在服务器上以 UTC 时间呈现,但在客户端上以区域设置时间呈现。
我不确定这是否是一个错误,或者我们是否应该自己处理这个问题。也不确定是否应该在 Remix 或 Styled 组件 GitHub 问题上询问这个问题。我已经开了一个issue https://github.com/remix-run/remix/issues/3645无论如何,也可以从 Remix 开始。
原帖
不确定,但可能与这些问题有关:
- Remix 2570 https://github.com/remix-run/remix/issues/2570
- Remix 2947 https://github.com/remix-run/remix/issues/2947
- React 24523 https://github.com/facebook/react/pull/24523
我通读了上面的内容和其他一些页面,我所能想到的就是更新一些依赖项。以下是可能相关的:
{
"react": "^18.2.0",
"styled-components": "^5.3.5"
"@remix-run/node": "^1.6.1",
"@remix-run/react": "^1.6.1",
"@remix-run/vercel": "^1.6.1",
"@vercel/node": "^2.2.0",
}
我的主要怀疑是它与样式组件有关,因为我之前在 Nextjs 上也遇到过类似的问题。但我的 app/root.tsx 和 app/entry.server.tsx 遵循这个例子 https://github.com/remix-run/remix/tree/dev/examples/styled-components对于样式组件非常接近:
// app/root.tsx
export default function App() {
const data = useLoaderData();
return (
<Html lang="en">
<head>
...
{typeof document === "undefined" ? "__STYLES__" : null}
</head>
<Body>
...
</Body>
</Html>
);
}
//app/entry.server.tsx
export default function handleRequest(
request: Request,
responseStatusCode: number,
responseHeaders: Headers,
remixContext: EntryContext
) {
const sheet = new ServerStyleSheet();
let markup = renderToString(
sheet.collectStyles(
<RemixServer context={remixContext} url={request.url} />
)
);
const styles = sheet.getStyleTags();
markup = markup.replace("__STYLES__", styles);
responseHeaders.set("Content-Type", "text/html");
return new Response("<!DOCTYPE html>" + markup, {
status: responseStatusCode,
headers: responseHeaders,
});
}
与该示例最大的区别似乎是,而不是使用hydrate
, I use hydrateRoot
正如我们对 React 18 所做的那样。不确定它是否与问题有任何关系:
// app/entry.client.tsx
import { RemixBrowser } from "@remix-run/react";
import { hydrateRoot } from "react-dom/client";
hydrateRoot(document, <RemixBrowser />);
The 有关 CSS-in-JS 库的 Remix 文档 https://remix.run/docs/en/v1/guides/styling#css-in-js-libraries说:“使用样式组件时,您可能会遇到水合警告。希望如此这个问题 https://github.com/styled-components/styled-components/issues/3660很快就会修复。”问题还没有解决,所以也许这个问题还没有解决方案。
但如果示例存储库有效,那么也许我错过了一些东西?