5

I am importing react-quill dynamically on the client side only using ssr: false. My functional component which is working fine, I want to add the quill-blot-formatter package to the modules part of my quill component.

My first roadblock is, I can't register this quill-blot-formatter with Quill as it shows:

ServerError
ReferenceError: document is not defined

This page is client rendered, therefore I don't understand where this error is coming from!

This is my code:

import dynamic from "next/dynamic";
import BlotFormatter from "quill-blot-formatter";

const QuillNoSSRWrapper = dynamic(import('react-quill'), {
    ssr: false,
    loading: () => <p>Loading...</p>,
})

Quill.register("modules/blotFormatter", BlotFormatter);

Here, I don't understand how to bring Quill out of react-quill now that it's being imported dynamically. Therefore, I think that Quill.register isn't working. Now, how do I register quill-blot-formatter with react-quill? Following the Next.js example with react-quill, I am not even importing react-quill as ReactQuill as is the default export in the package.

Then I declared the blotFormatter module like this.

const modules = {
    blotFormatter: {},  // here
    toolbar: [
        [{header: '1'}, {header: '2'}, {font: []}],
        [{size: []}],
        ...
    ],
}

const formats = ['header','font','size','bold','italic','underline',...]

And used in the render() method like this:

export default function NewContent() {
    ...
    render(
        <QuillNoSSRWrapper
            className={styles.quillTextArea}
            id="quilleditor"
            modules={modules}
            formats={formats}
            theme="snow"
            onChange={handleTextChange}
            readOnly={false}
        />
    );
}

So far, this QuillNoSSRWrapper child component is doing it's job fine, but, how do I use the quill-blot-formatter in it's formats?

forest
  • 1,312
  • 3
  • 20
  • 47

1 Answers1

5

UPDATE

You don't need another useEffect to register module you can do it when you importing ReactQuill.

const ReactQuill = dynamic(
  async () => {
    const { default: RQ } = await import("react-quill");
    const { default: BlotFormatter } = await import("quill-blot-formatter");
    RQ.Quill.register("modules/blotFormatter", BlotFormatter);
    return function forwardRef({ forwardedRef, ...props }) {
      return <RQ ref={forwardedRef} {...props} />;
    };
  },
  {
    ssr: false,
  }
);

With this code you importing ReactQuill, register you module and pass ref that you can use later see details below. So with this code you now don't need any state. Additionally you can add custom loading function to dynamic details here.


After one day of searching i found the solution. First of all you import dynamic ReactQuill.

import dynamic from 'react/dynamic'
const ReactQuill = dynamic(() => import("react-quill"), { ssr: false });

Or if you want to pass ref like this

const ReactQuill = dynamic(
  async () => {
    const { default: RQ } = await import("react-quill");
    // eslint-disable-next-line react/display-name
    return ({ forwardedRef, ...props }) => <RQ ref={forwardedRef} {...props} />;
  },
  {
    ssr: false,
  }
);

And then you can use ref like this <ReactQuill ... forwardedRef={quillRef}/>

So then after you imported ReactQuill on client side you need to register module i found this solution here it's looks strange and i had no time to improve it but it's work. Here the code.

  const loadQuill = async () => {
    return new Promise(async (resolve, reject) => {
      const Quill = await require("react-quill").Quill;
      const BlotFormatter = (await import("quill-blot-formatter")).default;
      resolve({ Quill, BlotFormatter });
    })
      .then(({ Quill, BlotFormatter }) => {
        Quill.register("modules/blotFormatter", BlotFormatter);
        return;
      })
      .then((value) => {
        setEnableEditor(true);
      });
  };

  useEffect(() => {
    loadQuill();
  }, []);

This code will execute on client side end register module. Also as you can see you need to declarate state enableEditor. And render ReactQuill only when enableEditor is true

{enableEditor && <ReactQuill ... />}

Looks bit wierd so maybe I will update it later