gpt4 book ai didi

javascript - NextJS 水合错误(文本内容与服务器呈现的 HTML 不匹配。)

转载 作者:行者123 更新时间:2023-12-05 00:38:44 27 4
gpt4 key购买 nike

仅在部署应用程序时出现两个错误,而不是在开发模式或本地构建中,这完全是另一个问题。
第一个错误:文本内容与服务器呈现的 HTML 不匹配。
第二个错误:补水时出错。因为错误发生在 Suspense 边界之外,所以整个根将切换到客户端渲染。
我发现错误是由我从 Unix 时间戳格式(current.dt)的 API 获得的时间格式引起的,但我不知道如何处理这个问题。我应该在服务器上格式化日期,即在 getServerSideProps 中吗?还是这些错误是由其他原因引起的?
编辑 :有错误的实时应用程序:https://weather-test-mu.vercel.app/
天气显示:

import type { Current, Location } from '../../types/typeWeatherApi';

const WeatherDisplay = ({
location,
current,
}: {
location: Location;
current: Current;
}) => {
// This causes the errors:
const hour = ('0' + new Date(current.dt * 1000).getHours()).slice(-2);
const minutes = ('0' + new Date(current.dt * 1000).getMinutes()).slice(-2);
const currentTime = `${hour}:${minutes}`;

return (
<article>
<h1>{location.name}</h1>
<p>{location.country}</p>
<p>{current.feels_like}</p>
{/* This causes the error: */}
<p>{currentTime}</p>
</article>
);
};

export default WeatherDisplay;
带有 getServerSideProps 的索引页面:
import axios from 'axios';
import { useState } from 'react';

import type { NextPage, GetServerSideProps } from 'next';
import type { Data, Location } from '../types/typeWeatherApi';

import { getCurrentWeather } from './api/currentWeather';
import { getCurrentLocation } from './api/currentLocation';

import WeatherDisplay from '../components/weather-display/weather-display';

const Home: NextPage = ({ initialWeather, initialLocation }: any) => {
const [location, setLocation] = useState<Location>(initialLocation);
const [weatherData, setWeatherData] = useState<Data>(initialWeather);
const [units, setUnits] = useState('metric');
const [lang, setLang] = useState('en');

const getGeolocationData = () => {
navigator.geolocation.getCurrentPosition(
(position) => {
axios
.get(
`/api/currentLocation?lon=${position.coords.longitude}&lat=${position.coords.latitude}`
)
.then((response) => setLocation(response.data[0]));
},
(error) => {
console.warn(`ERROR(${error.code}): ${error.message}`);
},
{
timeout: 10000,
maximumAge: 0,
}
);
};

const getCurrentWeather = async () => {
await axios
.get(
`/api/currentWeather?lon=${location.lon}&lat=${location.lat}&units=${units}&lang=${lang}`
)
.then((response) => setWeatherData(response.data))
.catch((error) => console.error(error));
};

return (
<>
<section>
<div>
<p>Latitude: {location.lat}</p>
<p>Longitude: {location.lon}</p>
</div>
<button onClick={getGeolocationData}>Get Current Location</button>

<button onClick={getCurrentWeather}>Get Current Weather</button>
</section>
<section className="current-weather">
<WeatherDisplay location={location} current={weatherData.current} />
</section>
</>
);
};

export const getServerSideProps: GetServerSideProps = async () => {
const defaultWeatherQuery = {
lat: '51.5072',
lon: '0.1276',
exclude: '',
units: 'metric',
lang: 'en',
};

const defaultLocationQuery = {
lat: defaultWeatherQuery.lat,
lon: defaultWeatherQuery.lon,
};

const defaultWeather = await getCurrentWeather(defaultWeatherQuery);
const defaultLocation = await getCurrentLocation(defaultLocationQuery);

return {
props: {
initialWeather: defaultWeather,
initialLocation: defaultLocation[0],
},
};
};

export default Home;

最佳答案

我得到了 GitHub discussions 的答复在 next.js 上,我会将其粘贴到这里,供遇到与我相同问题的任何人使用:
报价 icyJoseph :

Hi,

Yeah so this two errors are combined.

Because the client, on the first frame, needs to see the same HTML asthe server sent over, in order to place event listeners and placesiblings and children correctly, if there's an error while this isbeing done, React logs an error. This has happened all the way back toReact 17 AFAIK.

Problem number 2 kicks in with the new rendering root, which sees thisas a rendering error, which is unfriendly to concurrent features, sohydration fails and it throws the entire thing out the window.

At least that's how I interpret the second error. Lots of people justignored error number 1, during the entire 2 years React 17 was out,not saying you did, but many use libraries that did, and others justignored them. Possible work around

Time and randomness are two of the things that most commonly producethis.

I would attack this problem like this:

  1. Let the server render the time, but in UTC format
  2. Optionally, put CSS that makes this hidden, but still present on the layout (not display none)
  3. From the client, update to the correct time zone, also make the time visible
import { CSSProperties, useEffect, useState } from "react";
import { Example } from "../components/Example";

const TimeDisplay = ({ time }: { time: number }) => {
const [currentTime, setCurrentTime] = useState(() => {
const hour = ("0" + new Date(time * 1000).getUTCHours()).slice(-2);
const minutes = ("0" + new Date(time * 1000).getUTCMinutes()).slice(-2);

return `${hour}:${minutes} UTC`;
});

useEffect(() => {
setCurrentTime(() => {
const hour = ("0" + new Date(time * 1000).getHours()).slice(-2);
const minutes = ("0" + new Date(time * 1000).getMinutes()).slice(-2);

return `${hour}:${minutes}`;
});
}, [time]);

// optionally make this content take space, but remain invisible, to avoid layout shifts
// it's better to use a CSS class instead
const style: CSSProperties = {
visibility: currentTime.includes("UTC") ? "hidden" : "visible",
};

return (
<article>
<p style={style}>{currentTime}</p>
</article>
);
};

I'd recommend also mixing in the DateTimeFormat API,https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Intl/DateTimeFormat,which can take care of showing the time zone for you:

const date = new Date(Date.UTC(2012, 11, 20, 3, 0, 0, 200));

options = {
hour: 'numeric', minute: 'numeric', second: 'numeric',
timeZoneName: 'short'
};

console.log(new Intl.DateTimeFormat('sv-SE', options).format(date));

If I run the above on a repl, I get 3:00:00 AM UTC (this would bewhat your server sends), but if I run it on the browsers I get,4:00:00 CET.

The source code of you page contains the time seen by the server.

Since users arrive to you from different time zones, you have toaccount for a frame where you show UTC, and then you show the time forthe users time zone. Combining this with CSS visibility is good,because you can avoid layout shifts and such, the time will take itsplace, but it won't be visible.

Robots, crawlers still see the time, and for users with JS disabled,you could add a tag that makes the date visible again.

关于javascript - NextJS 水合错误(文本内容与服务器呈现的 HTML 不匹配。),我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/72837303/

27 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com