I have two errors only when the app is deployed, not in dev mode nor the local build, which is another issue altogether.
1st error: Text content does not match server-rendered HTML.
2nd error: There was an error while hydrating. Because the error happened outside of a Suspense boundary, the entire root will switch to client rendering.
I found out that the errors are caused by the formatting of the time that I get from an API in Unix timestamp format (current.dt), but I don't know how else to handle this. Should I format the date on the server i.e. in getServerSideProps? Or are these errors caused by something else?
Edit: Live app with errors: https://weather-test-mu.vercel.app/
WeatherDisplay:
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;
Index page with 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;