最新消息:雨落星辰是一个专注网站SEO优化、网站SEO诊断、搜索引擎研究、网络营销推广、网站策划运营及站长类的自媒体原创博客

reactjs - Hydration error only at Telegram's web view - Stack Overflow

programmeradmin1浏览0评论

I am getting a hydration error in my project, but it is appearing only in the telegram. I tried to open it from Safari, chrome, and Opera in my locale and also in production. There is no error. But when i opened it from the telegram i am getting this hydration error.

I am using "next": "15.1.6" and "react": "^19.0.0",

Since I see -playsinline="" at the bottom of the error, I thought it was because of the hero component that contains video background getting from a CDN.

You can reach out to the suspected code blocks from below;

this is my hero-video-player.tsx

"use client"

const HeroVideoPlayer = ({
    onLoad,
    onError,
    videoFile,
}: {
    onLoad: () => void
    onError: (error: string) => void
    videoFile: string
}) => {
    return (
        <video
            autoPlay={true}
            loop={true}
            muted={true}
            playsInline={true}
            preload="metadata" // Changed from auto to metadata for faster initial load
            controls={false}
            onLoadedData={onLoad}
            onError={(e) => {
                onError(
                    e.currentTarget.error?.message || "Video failed to load"
                )
            }}
            className={`absolute top-0 left-0 w-full h-full object-cover transition-opacity duration-500`}
            suppressHydrationWarning
            disablePictureInPicture // Add for better mobile compatibility
            controlsList="nodownload noplaybackrate" // Prevent download and speed controls
        >
            <source src={videoFile} type="video/mp4" />
            <track kind="captions" /> {/* Add empty track to prevent warning */}
        </video>
    )
}

export default HeroVideoPlayer

this is my hero-countdown.tsx

"use client"
import React, { useState, useEffect } from "react"
import CountdownBorder from "../../public/hero/countdown-border"
import { useTranslations } from "next-intl"

type HeroCountdownProps = {
    targetDate: string
}

function HeroCountdown({ targetDate }: HeroCountdownProps) {
    const t = useTranslations("hero")
    const [mounted, setMounted] = useState(false)

    const calculateTimeLeft = () => {
        const now = new Date().getTime()
        const difference = new Date(targetDate).getTime() - now

        if (difference <= 0) {
            return { days: 0, hours: 0, minutes: 0 }
        }

        const days = Math.floor(difference / (1000 * 60 * 60 * 24))
        const hours = Math.floor(
            (difference % (1000 * 60 * 60 * 24)) / (1000 * 60 * 60)
        )
        const minutes = Math.floor(
            (difference % (1000 * 60 * 60)) / (1000 * 60)
        )

        return { days, hours, minutes }
    }

    const [timeLeft, setTimeLeft] = useState({ days: 0, hours: 0, minutes: 0 })

    useEffect(() => {
        setMounted(true)
        setTimeLeft(calculateTimeLeft())

        const interval = setInterval(() => {
            setTimeLeft(calculateTimeLeft())
        }, 1000)

        return () => clearInterval(interval)
    }, [])

    if (!mounted) {
        return null // or a loading placeholder
    }

    return (
        <div className="w-full flex flex-row items-center justify-center space-x-2 sm:space-x-4 xl:space-x-12 h-28 xl:h-40 mx-auto mt-8 md:mx-0">
            <div className="h-full flex items-center justify-around space-x-4">
                <p className="text-white text-3xl lg:text-7xl font-bold">
                    {timeLeft && timeLeft?.days
                        ? timeLeft?.days?.toString().padStart(2, "0")
                        : "00"}
                </p>
                <p className="text-2xl lg:text-5xl font-extralight text-white">
                    {t("gun")}
                </p>
            </div>

            <CountdownBorder />

            <div className="h-full flex items-center justify-around space-x-4">
                <p className="text-white text-3xl lg:text-7xl font-bold">
                    {timeLeft && timeLeft?.hours
                        ? timeLeft?.hours?.toString().padStart(2, "0")
                        : "00"}
                </p>
                <p className="text-2xl lg:text-5xl font-extralight text-white">
                    {t("saat")}
                </p>
            </div>

            <CountdownBorder />
            <div className="h-full flex items-center justify-around space-x-4">
                <p className="text-white text-3xl lg:text-7xl font-bold">
                    {timeLeft && timeLeft?.minutes
                        ? timeLeft?.minutes?.toString().padStart(2, "0")
                        : "00"}
                </p>
                <p className="text-2xl lg:text-5xl font-extralight text-white">
                    {t("dakika")}
                </p>
            </div>
        </div>
    )
}

export default `HeroCountdown`

this is my hero.tsx

"use client"
import React, { useState, useEffect } from "react"
import { format } from "date-fns"
import HeroCountdown from "./hero-countdown"
import Link from "next/link"
import { useLocale, useTranslations } from "next-intl"
import { enGB, tr } from "date-fns/locale"
import { poppins, raleway } from "@/fonts"
import HeroVideoPlayer from "./hero-video-player"

type HeroProps = {
    time: string[]
    name: string
    abbreviation: string
    videoFile: string
}

function Hero({ time, name, abbreviation, videoFile }: HeroProps) {
    const t = useTranslations("hero")
    const currentLocale = useLocale()
    const [mounted, setMounted] = useState(false)
    const [formattedDates, setFormattedDates] = useState({
        startDate: "",
        endDate: "",
        month: "",
    })
    const [isVideoLoaded, setIsVideoLoaded] = useState(false)
    const [videoError, setVideoError] = useState<string | null>(null)

    useEffect(() => {
        setMounted(true)
        setFormattedDates({
            startDate: time[0] ? format(new Date(time[0]), "dd") : "",
            endDate: time[1] ? format(new Date(time[1]), "dd") : "",
            month: time[0]
                ? format(new Date(time[0]), "MMMM", {
                        locale:
                            currentLocale.toLowerCase() === "tr" ? tr : enGB,
                  })
                : "",
        })
    }, [time, currentLocale])

    return (
        <div className="w-full">
            <div className="relative w-full min-h-[calc(100vh-80px)] flex flex-1 justify-center items-end py-10 lg:py-0 lgulu:pb-20 2xl:pb-40 overflow-hidden">
                {mounted && (
                    <HeroVideoPlayer
                        onLoad={() => setIsVideoLoaded(true)}
                        onError={(msg) => setVideoError(msg)}
                        videoFile={videoFile}
                    />
                )}

                {/* Loading overlay */}
                <div
                    className={`absolute top-0 left-0 w-full h-full bg-black transition-opacity duration-500 ${
                        isVideoLoaded ? "opacity-0" : "opacity-100"
                    }`}
                />

                {/* Error display */}
                {videoError && (
                    <div className="absolute top-4 left-4 bg-red-500 text-white p-2 rounded">
                        {videoError}
                    </div>
                )}

                {/* Gradient overlay */}
                <div className="absolute top-0 left-0 w-full h-full bg-hero-gradient" />

                {/* Content */}
                <div className="relative flex flex-col justify-end items-center space-y-10 z-10">
                    <div className="flex flex-col">
                        <h2
                            className={`${poppins.className} font-semibold text-2xl lg:text-5xl text-[#F0F0F0] mb-4 text-center capitalize`}
                        >
                            {formattedDates.startDate} -{" "}
                            {formattedDates.endDate} {formattedDates.month}
                        </h2>
                        <h2
                            className={`${raleway.className} font-bold text-3xl lg:text-5xl text-[#ADE0F5] text-center uppercase px-6`}
                        >
                            {name}
                        </h2>
                        <h3
                            className={`${raleway.className} font-extrabold text-5xl lg:text-7xl text-white text-center uppercase tracking-[1.8rem]`}
                        >
                            {abbreviation}
                        </h3>
                    </div>

                    <HeroCountdown targetDate={time[0]} />

                    <div className="w-full flex flex-row flex-wrap items-center justify-center gap-3 py-5 lg:p-12">
                        <Link
                            href="/bildiri-gonderimi"
                            className="w-full max-w-72 bg-button-light-color text-xl text-text-light-color text-center font-medium p-3 rounded-xl hover:bg-zinc-300 transition-all duration-300"
                        >
                            {t("bildiri")}
                        </Link>

                        <Link
                            href="/katilimci"
                            className="w-full max-w-72 bg-main-red text-xl p-3 rounded-xl text-white font-medium text-center hover:bg-main-red/80 transition-all duration-300"
                        >
                            {t("kayit")}
                        </Link>

                        <Link
                            href="/konusmaci"
                            className="w-full max-w-72 bg-button-light-color text-xl text-text-light-color text-center font-medium p-3 rounded-xl hover:bg-zinc-300 transition-all duration-300"
                        >
                            {t("konusmaci")}
                        </Link>
                    </div>
                </div>
            </div>
        </div>
    )
}

export default Hero

and if you need at the page i am using hero component this is the page.tsx

import { GetCongressInfo } from "@/api/congress/get-congress"
import { GetFaq } from "@/api/faq/get-questions"
import { GetHero } from "@/api/hero/get-hero"
import { GetSocials } from "@/api/socials/get-socials"
import About from "@/components/about"
import EventInfo from "@/components/event-info"
import Faq from "@/components/faq"
import GeneralInfo from "@/components/general-info"
import Guests from "@/components/guests"
import OrganizationContact from "@/components/anization-contact"
import SendEmail from "@/components/send-email"
import Social from "@/components/social"
import { getLocale, getTranslations } from "next-intl/server"
import Hero from "@/components/hero"

export default async function Home() {
    const locale = await getLocale()
    const congress = await GetCongressInfo(locale.toLowerCase())
    const hero = await GetHero()
    const questions = await GetFaq(locale.toLowerCase())
    const social = await GetSocials()
    const t = await getTranslations("home")

    if (!congress) {
        return (
            <div className="flex flex-col min-h-[calc(100vh-80px)] flex-1 justify-center items-center space-y-4">
                <h2 className="text-main-red text-6xl font-extrabold text-center">
                    {t("error")}
                </h2>
                <h3 className="text-text-color text-3xl font-bold text-center">
                    {t("error-text")}
                </h3>
            </div>
        )
    }

    return (
        <div className="overflow-x-hidden">
            <Hero
                time={
                    congress && congress[0] && congress[0]?.date.length > 0
                        ? congress[0]?.date
                        : []
                }
                name={
                    congress && congress[0]?.name
                        ? (congress[0].name as string)
                        : ""
                }
                abbreviation={
                    congress && congress[0]?.name
                        ? (congress[0]?.abbreviation as string)
                        : ""
                }
                videoFile={hero ? (hero[0]?.hero_video_file as string) : ""}
            />

            <GeneralInfo address={congress ? congress[0]?.address : ""} />
            {/* <Register /> */}
            <Guests />
            {/* <SessionTable /> */}
            <EventInfo congress={congress ? congress[0] : null} />
            <About congress={congress ? congress[0] : null} />
            {/* <HonorList /> */}
            <OrganizationContact />
            <Social social={social && social[0] ? social[0] : null} />
            <Faq questions={questions ? questions : null} />
            <SendEmail email={"[email protected]"} />
        </div>
    )
}

发布评论

评论列表(0)

  1. 暂无评论