Nextjs:如何仅在客户端渲染上将 quill-blot-formatter 注册到动态导入的react-quill?

for*_*est 5 javascript reactjs quill next.js react-quill

我react-quill仅使用ssr: false. 我的功能组件工作正常,我想将quill-blot-formatter包添加到modules我的鹅毛笔组件的一部分。

我的第一个障碍是,我无法注册它,quill-blot-formatter如图Quill所示:

ServerError
ReferenceError: document is not defined
Run Code Online (Sandbox Code Playgroud)

该页面是客户端呈现的,因此我不明白这个错误来自哪里!

这是我的代码:

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);
Run Code Online (Sandbox Code Playgroud)

在这里,我不明白如何让它Quill动态导入react-quill。因此,我认为这Quill.register是行不通的。现在,我如何quill-blot-formatter注册react-quill?在使用React-quill 的 Next.js 示例之后,我什至没有像ReactQuill包中的默认导出那样导入 React-quill 。

然后我blotFormatter像这样声明了该模块。

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

const formats = ['header','font','size','bold','italic','underline',...]
Run Code Online (Sandbox Code Playgroud)

render()并在这样的方法中使用:

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

到目前为止,这个QuillNoSSRWrapper子组件做得很好,但是,我如何使用它quill-blot-formatter的formats?

Yar*_*nko 6

更新

您不需要另一个 useEffect 来注册模块,您可以在导入 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,
  }
);
Run Code Online (Sandbox Code Playgroud)

使用此代码,您可以导入 ReactQuill,注册您的模块并传递稍后可以使用的引用,请参阅下面的详细信息。因此,使用此代码,您现在不需要任何状态。此外,您还可以在此处向动态详细信息添加自定义加载功能。


经过一天的搜索,我找到了解决方案。首先,导入动态 ReactQuill。

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

或者如果你想像这样传递 ref

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,
  }
);
Run Code Online (Sandbox Code Playgroud)

然后你可以像这样使用 ref<ReactQuill ... forwardedRef={quillRef}/>

因此,在客户端导入 ReactQuill 后,您需要注册模块,我在这里发现了这个解决方案,它看起来很奇怪,我没有时间改进它,但它可以工作。这是代码。

  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();
  }, []);
Run Code Online (Sandbox Code Playgroud)

该代码将在客户端寄存器模块上执行。另外,正如您所看到的,您需要声明状态enableEditor。并且仅当enableEditor为true时渲染ReactQuill

{enableEditor && <ReactQuill ... />}
Run Code Online (Sandbox Code Playgroud)

看起来有点奇怪所以也许我稍后会更新