Next.js Discord

Discord Forum

How can I fix these 3 Hydration Errors ?

Answered
Sun bear posted this in #help-forum
Open in Discord
Avatar
Sun bearOP
Here is my code:

//app/[lang]/signup/page.tsx
import { getDictionary } from '@/app/translation/dictionary';
import SignUp from '@/components/SignUpProcess/page';
import type { Dictionary } from '@/app/translation/dictionaryTypes';

type Props = {
  params: {
    lang: "en" | "ro";
  }
}

const Page = async (props: Props) => {
    const data = await getDictionary(props.params.lang);
    return (
        <>
            <SignUp dictionary={data} />
        </>
    );
}

export default Page;

I can share more of the code if needed as in the code from the other components used by my page.
Image
Image
Image
Answered by Cape horse mackerel
you can try to create a hook useMounted.ts
import { useEffect, useState } from "react";

/**
 * Fixes "Hydration failed because the initial UI does not match what was rendered on the server"
 * @returns {boolean} - A boolean value indicating whether the component is currently mounted.
 */
export default function useMounted(): boolean {
  const [mounted, setMounted] = useState(false);

  useEffect(() => {
    setMounted(true);

    return () => setMounted(false);
  }, []);

  return mounted;
}

give it a try
View full answer

56 Replies

Avatar
Cape horse mackerel
you can try to create a hook useMounted.ts
import { useEffect, useState } from "react";

/**
 * Fixes "Hydration failed because the initial UI does not match what was rendered on the server"
 * @returns {boolean} - A boolean value indicating whether the component is currently mounted.
 */
export default function useMounted(): boolean {
  const [mounted, setMounted] = useState(false);

  useEffect(() => {
    setMounted(true);

    return () => setMounted(false);
  }, []);

  return mounted;
}

give it a try
Answer
Avatar
Cape horse mackerel
usage
export default function YourComponent() {
  const mounted = useMounted();
  // ... the rest of the code

  // this should be on the last line before return
  if(!mounted) return null;
  return <div></div>
}
Avatar
Sun bearOP
Oh my, I just realised something. You helped me with fixing the type error in my other thread but after updating the code it looks like I now get the same error in this page.

// app/[lang]/signup/page.tsx
"use client";
import React, { useState, ChangeEvent } from 'react';
import TopNavigationBar from '../TopNavigationBar';
import PersonalInformation from './PersonalInformation';
import type { Dictionary } from '@/app/translation/dictionaryTypes';

const SignUp = ({dictionary})=>{
    // State to manage form steps
    const [currentStep, setCurrentStep] = useState(0);

    // State to manage dictionary data
    //const [dictionary, setDictionary] = useState<Dictionary | null>(null);

    // Define the structure of your form data
    const [formData, setFormData] = useState({
        firstName: '',
        lastName: '',
        country: '',
        dateOfBirth: '',
        email: '',
        password: ''
    });

    // Handle change in form fields
    const handleChange = (event: ChangeEvent<HTMLInputElement | HTMLSelectElement>) => {
        const { name, value } = event.target;
        setFormData({ ...formData, [name]: value });
    };

    // Define the components for each step
    const steps = [
        <PersonalInformation data={formData} handleChange={handleChange} />,
        // Add other steps here as needed...
    ];

    const signUp = async (event: React.FormEvent<HTMLFormElement>) => {
        event.preventDefault();
        // Implement sign-up logic with formData here
    };

    return (
        //UI
    );
}

export default SignUp;


Do I have to import the props here as well?
Image
Avatar
Cape horse mackerel
const SignUp = ({ dictionary }: Dictionary) => {}
Avatar
Sun bearOP
Image
And now the other page gives errors as well
Image
Haha 😅
If I change it back to how it was the other page doesn't give errors anymore but this page does as you can see.
Image
So it looks like the changes we make here influence what happens on the other page
Image
Avatar
Sun bearOP
// app/[lang]/signup/page.tsx
import React from 'react';
import { getDictionary } from '@/app/translation/dictionary';
import SignUp from '@/components/SignUpProcess/page';
import type { Dictionary } from '@/app/translation/dictionaryTypes';
import useMounted from '@/hooks/useMounted';

type Props = {
  params: {
    lang: "en" | "ro";
  };
};

const Page = async (props: Props) => {
  const mounted = useMounted();
  const data = await getDictionary(props.params.lang);

  if (!mounted) return null;

  return (
    <>
      <SignUp dictionary={data} />
    </>
  );
};

export default Page;

As for the hook suggestion, I am getting this error when loading the page.
Image
Avatar
Cape horse mackerel
// page.tsx
"use client";
// ...rest of the code
const Page = () => {}

this is for the hook
Avatar
Sun bearOP
Image
I am already using use client for the page.tsx, the idea is for the page.tsx inside the actual signup page to stay SSR.
Avatar
Cape horse mackerel
then try to use hook within SignUpProcess/page.tsx
Avatar
Sun bearOP
That is already what I'm doing
Image
Haha, sorry if this is confusing
Avatar
Cape horse mackerel
no, you're not
you're using hook within [lang]/signup/page.tsx
Avatar
Sun bearOP
Oh, my bad, I've misread that.
Avatar
Cape horse mackerel
should use it within components/SignUpProcess/page.tsx
Avatar
Sun bearOP
Wow, somehow that also fixed the other errors in regards with the dictionary.
Do you know why that is ?
Image
No more errors in any of the pages 👀
Image
This is the only issue left now
Image
The page loads though
Avatar
Anay
And here, in type Props, I recommend setting lang to string
Avatar
Sun bearOP
I am getting this error again now
Image
Image
Avatar
Anay
Wait do you only support 2 languages?
If you only support 2, then change it back
Avatar
Sun bearOP
Uh, I plan to support more, for now it's only 2 because I will add the rest of them at the end.
Avatar
Anay
Then change it back then
Avatar
Sun bearOP
I think it makes the development a bit easier
But why doesn't it work with 2 ?
Like what's the difference.
Avatar
Anay
It’ll work with 2, but since you only have 2, I’ll recommend that only.
You’ll have to change dictionary.tsx then
Like change the argument
Avatar
Sun bearOP
// dictionary.ts
import 'server-only';
import type { Locale } from '@/i18n.config';
import type { Dictionary } from './dictionaryTypes';

const dictionaries = {
  en: () => import('./dictionaries/en.json').then(module => module.default as Dictionary),
  ro: () => import('./dictionaries/ro.json').then(module => module.default as Dictionary)
};

export const getDictionary = async (locale: Locale): Promise<Dictionary> => {
  if (!dictionaries[locale]) {
    // Return a default dictionary or one of the existing ones
    return dictionaries['en']();
  }
  return dictionaries[locale]();
};
This is my dictionary.ts file
Avatar
Anay
Show i18n.config
Avatar
Sun bearOP
//i18n.config.ts
export const i18n = {
    defaultLocale: 'en',
    locales: ['en', 'ro']
  } as const
  
  export type Locale = (typeof i18n)['locales'][number]
Avatar
Anay
I’m not sure as I’m new to ts. Id prefer not to share as I don’t have complete knowledge
Avatar
Sun bearOP
Oh okay, totally understandable. Then I will leave it as it is for now and sort it out at a later point in time.
But I appreciate you tried to help me with that as well!
Avatar
Anay
Great idea.
No problem
And can you dm me 1 min
Avatar
Sun bearOP
Of course
It looks like it won't let me dm you, you probably do not accept messages from other people.
Avatar
Anay
Maybe it’s with you. It’s enabled in my server settings
Avatar
Sun bearOP
Yup, that was it.