6

I'm trying to get my custom formfield to play nicely with NextJS. But there seems to be an issue with the hydration.

This is my webcomponent:

@Component({
  tag: 'test-checkbox',
  shadow: false,
})
export class TestCheckbox {
  @Prop() name: string;
  @Prop() value: boolean;
  @Prop() label: string;
  @Prop() innerValue: string;

  render() {
    const { value, name } = this;

    return (
      <div>
        <label htmlFor={this.name}>{this.label}</label>
        <input type="checkbox" name={name} id={name} checked={!!value} />
      </div>
    );
  }
}

I'm using the Stencil ReactJS wrappers, so the code in NextJS will look something like this:

const Form = () => {
  const formRef = useRef();
  
  const handleInput = (e) => {
    ///
  };

  const handleSubmit = (e) => {
    ///
  };

  return (
      <form ref={formRef} onSubmit={handleSubmit}>
        <TestInput name='damn' label='labeltest' onInput={handleInput} />
        <button type='submit'>submit</button>
      </form>
  );
};

export default Form;

When I run this component in my nextJS app, I will get the following error:

Unhandled Runtime Error
Error: Hydration failed because the initial UI does not match what was rendered on the server.

When I set shadow to true inside my webcomponent I do not get the error, but now the formfield will not show up in my FormData on submit.

I'm guessing the hydration issue is because the stencil components will render the inside of their component a fraction too early or a fraction too late, so that what is on the server is different than on the client.

Is there a way maybe to suppress the notification (It is not there on production and besides the messages everything seems to work fine) Or is there a way to load the stencil files in time, so that server and client have the correct data to start hydration?

1 Answers1

0

I've found a way to overcome this issue, it's to disable the Server Side Rendering from Next.js. To apply it to your case, when you import form component, instead of

import Form from './form'

const Page = () => (
<>
  <Form />
</>
)

you should use the dynamic import

import dynamic from 'next/dynamic'

const FormWithoutSSR = dynamic(() => import('./form'), {
    ssr: false
})

const Page = () => (
<>
  <FormWithoutSSR />
</>
)

You have different approaches in https://javascript.plainenglish.io/how-to-solve-hydration-error-in-next-js-a50ec54bfc02