You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

React自定义Skeleton组件触发Hydration不匹配错误求助

解决自定义Skeleton组件的Hydration不匹配错误

问题根源分析

触发Hydration错误的核心是服务端与客户端渲染的DOM结构/内容不一致,你的组件存在几个关键问题:

  • 列表渲染缺少唯一key:Array.map生成元素时未指定key,React无法在Hydration阶段准确匹配服务端和客户端的列表项,导致DOM不匹配。
  • 空文本节点与特殊字符:div内的隐形特殊字符(‌)可能在服务端和客户端解析不一致;{inline ? '' : <br />}会生成空文本节点,也会引发匹配问题。
  • 样式空值处理不当:height默认设为空字符串'',会在style属性中生成无效的height: "",服务端和客户端对这种无效样式的渲染可能存在差异。

修复后的组件代码

interface SkeletonProps {
    width?: number;
    height?: number;
    count?: number;
    className?: string;
    style?: React.CSSProperties;
    inline?: boolean;
}

export default function Skeleton({ className, width, height, count = 1, style, inline }: SkeletonProps) {
    const skeletonStyles = {
        width: width ? `${width}px` : '100%',
        // 将空字符串改为undefined,避免生成无效样式属性
        height: height ? `${height}px` : undefined,
    };

    return (
        <>
            {Array(count).fill(0).map((_, index) => {
                // 使用index作为key(如果count固定且无排序变化,index足够用)
                return (
                    <React.Fragment key={index}>
                        <div className={`skeleton ${className || ''}`} style={{ ...skeletonStyles, ...style }}>
                            {/* 用&nbsp;替代特殊字符,或者直接留空(如果不需要占位文本) */}
                            &nbsp;
                        </div>
                        {/* 改用逻辑与,避免生成空文本节点 */}
                        {!inline && <br />}
                    </React.Fragment>
                );
            })}
        </>
    );
}

关键修复点说明

  1. 添加列表key:给map返回的每个元素添加key={index},确保React能准确匹配服务端和客户端的列表元素。如果后续有动态排序需求,建议使用业务唯一ID作为key。
  2. 优化条件渲染:把{inline ? '' : <br />}改成{!inline && <br />},避免生成多余的空文本节点,消除DOM结构差异。
  3. 修正样式空值:将height的默认值从''改为undefined,这样React不会渲染无效的height属性,保证服务端和客户端样式渲染一致。
  4. 替换特殊字符:把div内的隐形特殊字符换成&nbsp;或者直接移除(如果不需要占位内容),避免解析差异。

内容的提问来源于stack exchange,提问作者Alex

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.31 14:20:33