Remix 开发小技巧(四)

2023-10-15 10:04
文章标签 技巧 开发 remix

本文主要是介绍Remix 开发小技巧(四),希望对大家解决编程问题提供一定的参考价值,需要的开发者们随着小编来一起学习吧!

文章目录

  • 解决水合错误
    • 水合错误是什么样的?
    • 🔥 提示:对 HTML 进行差异以查找确切原因
    • 浏览器扩展程序或广告拦截器
    • 无效的 HTML
    • 第三方脚本或非 React 包
    • JS库中的CSS
    • 字符编码
    • 时区不匹配
    • 非幂等函数,如 UUID
    • 基于客户端数据呈现
  • 逐步增强客户端渲染,以避免 Remix 中的 SSR 水合问题

解决水合错误

人们通常将水合错误描述为服务器生成的HTML与浏览器生成的HTML不匹配,但这并不是故事的全部。

为了解释这一点,让我们看看 React 的服务器端渲染是如何工作的。大多数实现都遵循相同的步骤。

  1. 服务器呈现页面并向客户端提供 HTML。
  2. 浏览器加载页面,React 开始运行。
  3. React 重新渲染页面并生成自己的 HTML。
  4. 然后,React 将它生成的 HTML 与浏览器显示的 HTML 进行比较。
  5. 如果 HTML 匹配,那就太好了!否则,React 将抛出一个水合错误。

由于 React 正在将它生成的 HTML 与浏览器显示的 HTML 进行比较,因此在服务器发送它和 React 开始运行的时间之间更改 HTML 的任何内容都可能导致水合错误。

水合错误是什么样的?

水合错误的主要症状是 React 会放弃其服务器渲染的内容并执行完整的客户端渲染。这可能会导致页面闪烁并完全重新获取数据。

在开发中,您将看到稍微有用的错误消息。

  • 冻结失败,因为初始 UI 与服务器上呈现的内容不匹配。
  • 警告:应服务器 HTML 包含 中的 匹配 项。

🔥 提示:对 HTML 进行差异以查找确切原因

在我们继续讨论水合错误的常见原因之前,一个超级方便的技巧是将服务器发送的 HTML 与 React 生成的 HTML 进行差异。

有三个地方可以寻找这个。

  • 浏览器开发工具中的“网络”选项卡将显示服务器发送的 HTML。
  • 如果删除 root.tsx 中的 , Remix 将不会水合,您可以使用 View Source 查看在水合之前存在的 HTML。
  • 如果比较这三个 HTML 源,通常可以找到水化错误的确切原因。

有许多在线HTML比较工具,只需谷歌一个并从三个来源中的两个粘贴HTML即可。

浏览器扩展程序或广告拦截器

浏览器扩展程序通常有权修改任何网站(包括您的应用)的实时页面内容。如果扩展在 React 有机会比较它之前修改了 HTML,这可能会导致水化错误。

在隐身/无痕浏览窗口中试用您的应用,并禁用所有扩展程序。如果错误消失,您就知道扩展程序导致了问题,并且您可能对此无能为力。

还有一些桌面级广告拦截器和安全软件可能会导致类似的问题。如果您正在运行其中之一,请尝试禁用它或在另一台设备上进行测试。您可以在工具中为您的网站添加例外。

无效的 HTML

浏览器会进行大量纠错,以确保即使HTML格式不正确,页面也能合理呈现。

例如,如果您非法嵌套在

,浏览器将移动 的

外部以使 HTML 有效。

HTML 中禁止嵌套表单,因此,如果表单中有表单,浏览器会将嵌套表单移动到父表单之外,成为其同级表单。

当 React 补水时,它会将它生成的 HTML 与浏览器显示的 HTML 进行比较。如果浏览器移动元素,React 将抛出水化错误。

这里的解决方案是编写有效的 HTML。

第三方脚本或非 React 包

第三方脚本也可能修改页面上的 HTML。这在HotJar或Google Tag Manager(GTM)等分析脚本中尤其常见。如果您使用的是第三方脚本,请尝试将其删除,看看错误是否消失。

如果这是问题所在,您可以在 React 完成补水后运行脚本。例如,可以使用 在 useEffect 第一次渲染后运行脚本。

JS库中的CSS

CSS 中的 CSS 是一种设置 React 应用程序样式的方法,它将样式定义为渲染的副作用。这意味着当服务器呈现页面时,样式不可用,并且服务器发送到客户端的 HTML 将与 React 生成的 HTML 不匹配。

Chakra、Emotion 和 Material UI 是 JS 库中流行的 CSS,存在此问题。

字符编码

字符编码问题通常会显示明显的错误消息,因此易于诊断。

[Error] Warning: Text content did not match.Server: "â€"Client: "’"

当服务器和客户端的字符编码不匹配时,会发生这种情况。最常见的原因是服务器正在发送 UTF-8 编码的文本,但客户端将其解释为 ISO-8859-1。

要解决此问题,请将以下元标记添加到 HTML 中。

<metahttp-equiv="Content-Type"content="text/html;charset=utf-8"
/>

时区不匹配

可能最臭名昭著的罪魁祸首是 Date 对象。约会很复杂,你越少处理它们,你的生活就会越快乐。

当javascript尝试创建日期时,它将使用运行它的机器的时区。这意味着,如果您在服务器上创建一个日期并将其发送到客户端,客户端将在其自己的时区中创建一个日期,该时区将与服务器的时区不同。

如果您尝试呈现日期,则当服务器日期与客户端日期不同时,您每天都会在接近午夜时遇到这些补水问题。

  • 最简单的解决方案是在服务器上将日期格式化为字符串并将其发送到客户端。
  • 客户端可以将时区/区域设置信息发送到服务器,服务器可以使用它来创建一个假日期,该日期将在冻结期间与客户端的时区匹配。
  • 基于客户端数据呈现部分中的更多解决方案: https://www.jacobparis.com/content/remix-hydration-errors#rendering-based-on-client-data

非幂等函数,如 UUID

如果您使用的是非幂等函数(例如 uuid 生成唯一 ID),则可能会收到冻结错误。这是因为服务器和客户端将生成不同的 ID。

您可以在服务器上生成 ID 并发送到客户端,也可以将种子传递给函数,以便服务器和客户端生成相同的 ID。

基于客户端数据呈现

某些数据仅存在于客户端上,在服务器首次呈现页面时将不可用。

例如,您可能有一个从本地存储中获取默认值的输入。如果在服务器上将输入呈现为空,然后在客户端上填充它,则会出现冻结错误和难看的空输入闪烁。

服务器无法知道客户端想要渲染的内容,因此您的解决方案是找到一种方法来隐藏服务器上和初始水合渲染期间的元素。

来自Remix Utils的useHydrated钩子将为您提供一个 isHydrated 布尔值,您可以使用该布尔值有条件地渲染元素。

This is the easiest solution but has its own caveats
这是最简单的解决方案,但有其自身的注意事项

  • 它仍然会产生空内容的闪光,尽管您可以使用淡入淡出效果来使其不那么刺耳。
  • 如果 javascript 加载失败,这些元素根本不会出现,从而打破了渐进式增强的故事。

我的首选解决方案是使用 ProgressiveClientOnly 组件,该组件将使用 CSS 隐藏服务器呈现的内容,并在 Javascript 可用时将其交换为客户端内容,否则它将显示服务器内容。

逐步增强客户端渲染,以避免 Remix 中的 SSR 水合问题

对于服务器端渲染的所有好处,也有一些事情变得更加困难,例如在客户端和服务器中显示相同的日期。

每当服务器可以渲染的内容与客户端可以呈现的内容不匹配时,您都会遇到问题。

处理不当的网站最终会出现无样式内容(FOUC)或不正确内容的闪烁(FOIC)。您可能会遇到补水错误,并导致您的网站完全依赖服务器端渲染。

有些人试图通过仅在客户端上呈现某些元素来解决此问题。这是避免不匹配的可靠方法,但这也意味着没有javascript的用户将永远不会看到该内容。

没有javascript的用户将获得服务器上呈现的任何版本的页面,因此,如果要逐步增强,服务器必须呈现内容。

也就是说,javascript将适用于大多数网站的大多数用户,因此我们想要针对这种情况进行优化。

我们希望确保该网站在没有Javascript的情况下运行,但是如果这意味着该网站对大多数用户来说效果很好,那么我可以让这种体验有点笨拙。

由于我们必须在服务器上呈现内容,但我们不想立即向用户显示它,因此我们需要以某种方式隐藏它。Javascript解决方案在这里不起作用。即使你告诉 React 立即隐藏它,在 React 接管之前,服务器渲染页面仍然会有闪光。

我们剩下的是一个CSS解决方案。

我构建了一个自定义包装器组件,该组件隐藏其内容,直到页面加载。如果禁用JS,它将通过CSS动画显示它们。如果没有,则可以通过传入类名来自定义行为。

import { useHydrated } from "remix-utils"
export function ProgressiveClientOnly({children,className = "",
}: {children: React.ReactNode | (() => React.ReactNode)className: string
}) {const isHydrated = useHydrated()return (<divclassName={// Create this class in your tailwind configisHydrated ? className : "animate-appear"}>{typeof children === "function"? children(): children}</div>)
}

该 animate-appear 类是一个自定义 CSS 动画,它使元素在延迟后突然出现。

module.exports = {theme: {extend: {animation: {appear: "appear 300ms",},keyframes: {appear: {"0%, 99%": {height: "0",width: "0",opacity: "0",},"100%": {height: "auto",width: "auto",opacity: "1",},},},},},
}

这篇关于Remix 开发小技巧(四)的文章就介绍到这儿,希望我们推荐的文章对编程师们有所帮助!



http://www.chinasem.cn/article/216973

相关文章

qt5cored.dll报错怎么解决? 电脑qt5cored.dll文件丢失修复技巧

《qt5cored.dll报错怎么解决?电脑qt5cored.dll文件丢失修复技巧》在进行软件安装或运行程序时,有时会遇到由于找不到qt5core.dll,无法继续执行代码,这个问题可能是由于该文... 遇到qt5cored.dll文件错误时,可能会导致基于 Qt 开发的应用程序无法正常运行或启动。这种错

mtu设置多少网速最快? 路由器MTU设置最佳网速的技巧

《mtu设置多少网速最快?路由器MTU设置最佳网速的技巧》mtu设置多少网速最快?想要通过设置路由器mtu获得最佳网速,该怎么设置呢?下面我们就来看看路由器MTU设置最佳网速的技巧... 答:1500 MTU值指的是在网络传输中数据包的最大值,合理的设置MTU 值可以让网络更快!mtu设置可以优化不同的网

Python实例题之pygame开发打飞机游戏实例代码

《Python实例题之pygame开发打飞机游戏实例代码》对于python的学习者,能够写出一个飞机大战的程序代码,是不是感觉到非常的开心,:本文主要介绍Python实例题之pygame开发打飞机... 目录题目pygame-aircraft-game使用 Pygame 开发的打飞机游戏脚本代码解释初始化部

使用Python开发一个现代化屏幕取色器

《使用Python开发一个现代化屏幕取色器》在UI设计、网页开发等场景中,颜色拾取是高频需求,:本文主要介绍如何使用Python开发一个现代化屏幕取色器,有需要的小伙伴可以参考一下... 目录一、项目概述二、核心功能解析2.1 实时颜色追踪2.2 智能颜色显示三、效果展示四、实现步骤详解4.1 环境配置4.

MySQL JSON 查询中的对象与数组技巧及查询示例

《MySQLJSON查询中的对象与数组技巧及查询示例》MySQL中JSON对象和JSON数组查询的详细介绍及带有WHERE条件的查询示例,本文给大家介绍的非常详细,mysqljson查询示例相关知... 目录jsON 对象查询1. JSON_CONTAINS2. JSON_EXTRACT3. JSON_TA

Python使用smtplib库开发一个邮件自动发送工具

《Python使用smtplib库开发一个邮件自动发送工具》在现代软件开发中,自动化邮件发送是一个非常实用的功能,无论是系统通知、营销邮件、还是日常工作报告,Python的smtplib库都能帮助我们... 目录代码实现与知识点解析1. 导入必要的库2. 配置邮件服务器参数3. 创建邮件发送类4. 实现邮件

Spring @RequestMapping 注解及使用技巧详解

《Spring@RequestMapping注解及使用技巧详解》@RequestMapping是SpringMVC中定义请求映射规则的核心注解,用于将HTTP请求映射到Controller处理方法... 目录一、核心作用二、关键参数说明三、快捷组合注解四、动态路径参数(@PathVariable)五、匹配请

基于Python开发一个有趣的工作时长计算器

《基于Python开发一个有趣的工作时长计算器》随着远程办公和弹性工作制的兴起,个人及团队对于工作时长的准确统计需求日益增长,本文将使用Python和PyQt5打造一个工作时长计算器,感兴趣的小伙伴可... 目录概述功能介绍界面展示php软件使用步骤说明代码详解1.窗口初始化与布局2.工作时长计算核心逻辑3

如何确定哪些软件是Mac系统自带的? Mac系统内置应用查看技巧

《如何确定哪些软件是Mac系统自带的?Mac系统内置应用查看技巧》如何确定哪些软件是Mac系统自带的?mac系统中有很多自带的应用,想要看看哪些是系统自带,该怎么查看呢?下面我们就来看看Mac系统内... 在MAC电脑上,可以使用以下方法来确定哪些软件是系统自带的:1.应用程序文件夹打开应用程序文件夹

python web 开发之Flask中间件与请求处理钩子的最佳实践

《pythonweb开发之Flask中间件与请求处理钩子的最佳实践》Flask作为轻量级Web框架,提供了灵活的请求处理机制,中间件和请求钩子允许开发者在请求处理的不同阶段插入自定义逻辑,实现诸如... 目录Flask中间件与请求处理钩子完全指南1. 引言2. 请求处理生命周期概述3. 请求钩子详解3.1