窗口未定义 - 在SSR模式下使用React-Draft-Wysiwyg和Next.js

15

我正在开发一个富文本编辑器,用于将普通 HTML 转换为编辑器内容并进行服务器端渲染(SSR)的 Next.js 项目。但是我遇到了“window is not defined”错误,因此我在该 GitHub 链接 上寻找解决方案。

该项目使用了 Next.js 的动态导入功能。

与其直接导入 Editor:import { Editor } from "react-draft-wysiwyg";

它使用以下代码来动态导入编辑器:

const Editor = dynamic(
  () => {
    return import("react-draft-wysiwyg").then(mod => mod.Editor);
  },
  { ssr: false }
);

但是尽管我已经安装了 react-draft-wysiwyg 模块,我仍然遇到这个错误。

ModuleParseError: Module parse failed: Unexpected token (19:9)
You may need an appropriate loader to handle this file type.
| import dynamic from "next/dynamic";
| var Editor = dynamic(function () {
>   return import("react-draft-wysiwyg").then(function (mod) {
|     return mod.Editor;
|   });

这是我的全部代码

import React, { Component } from "react";
import { EditorState } from "draft-js";
// import { Editor } from "react-draft-wysiwyg";
import dynamic from "next/dynamic";

const Editor = dynamic(
  () => {
    return import("react-draft-wysiwyg").then(mod => mod.Editor);
  },
  { ssr: false }
);

class MyEditor extends Component {
  constructor(props) {
    super(props);
    this.state = { editorState: EditorState.createEmpty() };
  }

  onEditorStateChange = editorState => {
    this.setState({ editorState });
  };

  render() {
    const { editorState } = this.state;

    return (
      <div>
        <Editor
          editorState={editorState}
          wrapperClassName="rich-editor demo-wrapper"
          editorClassName="demo-editor"
          onEditorStateChange={this.onEditorStateChange}
          placeholder="The message goes here..."
        />
      </div>
    );
  }
}

export default MyEditor;

请大家帮帮我,谢谢。


我在日志中遇到了一些问题:\react-draft-wysiwyg.js:1:393) undefined window ... 这是同一个错误点吗? - Nikola Lukic
什么是错误信息?我认为这是因为我们在服务器端渲染组件,而窗口未定义。 - elpmid
1
实际上,我的代码和你的一样,在我的项目中运行良好。 - Dastan
6个回答

17

这里有一个解决方法

import dynamic from 'next/dynamic'
import { EditorProps } from 'react-draft-wysiwyg'

// install @types/draft-js @types/react-draft-wysiwyg and @types/draft-js @types/react-draft-wysiwyg for types

const Editor = dynamic<EditorProps>(
  () => import('react-draft-wysiwyg').then((mod) => mod.Editor),
  { ssr: false }
)

1
动态导入修复了安装类型时窗口未定义的错误,使用EditorProps修复了Typescript中的类型错误。 - Ankush Chauhan
使用这个解决方案时,我遇到了一个类型错误:类型为'() => Promise<ComponentClass<EditorProps, any> | FunctionComponent<EditorProps> | ComponentModule<EditorProps> | typeof Editor>'的参数无法赋值给类型为'DynamicOptions<EditorProps> | Loader<EditorProps>'的参数。 - undefined

8

动态的那个对我有用

import dynamic from 'next/dynamic';
const Editor = dynamic(
  () => import('react-draft-wysiwyg').then((mod) => mod.Editor),
  { ssr: false }
)
import "react-draft-wysiwyg/dist/react-draft-wysiwyg.css";

const TextEditor = () => {
  return (
    <>
      <div className="container my-5">
        <Editor
          toolbarClassName="toolbarClassName"
          wrapperClassName="wrapperClassName"
          editorClassName="editorClassName"
        />
      </div>
    </>
  )
}

export default TextEditor


2
使用Strapi后端的Next.js和Draft.js WYSWYG,创建和查看带有图像上传的文章。
import React, { Component } from 'react'
import { EditorState, convertToRaw } from 'draft-js';
import draftToHtml from 'draftjs-to-html'; 
import dynamic from 'next/dynamic';
const Editor = dynamic(
() => import('react-draft-wysiwyg').then(mod => mod.Editor),
{ ssr: false })  

import "react-draft-wysiwyg/dist/react-draft-wysiwyg.css";


export default class ArticleEditor extends Component {

constructor(props) {
    super(props);

    this.state = {
        editorState: EditorState.createEmpty()
    };
}

onEditorStateChange = (editorState) => {
    this.setState({
        editorState,
    });
    this.props.handleContent(
        convertToRaw(editorState.getCurrentContent()
    ));
};

  uploadImageCallBack = async (file) => {
    const imgData = await apiClient.uploadInlineImageForArticle(file);
    return Promise.resolve({ data: { 
      link: `${process.env.NEXT_PUBLIC_API_URL}${imgData[0].formats.small.url}`
    }});
  }

render() {
    const { editorState } = this.state;
    return (
        <>
            <Editor
                editorState={editorState}
                toolbarClassName="toolbar-class"
                wrapperClassName="wrapper-class"
                editorClassName="editor-class"
                onEditorStateChange={this.onEditorStateChange}
                toolbar={{
                    options: ['inline', 'blockType', 'fontSize', 'fontFamily', 'list', 'textAlign', 'colorPicker', 'link', 'embedded', 'emoji', 'image', 'history'],
                    inline: { inDropdown: true },
                    list: { inDropdown: true },
                    textAlign: { inDropdown: true },
                    link: { inDropdown: true },
                    history: { inDropdown: true },
                    image: {
                        urlEnabled: true,
                        uploadEnabled: true,
                        uploadCallback: this.uploadImageCallBack,
                        previewImage: true,
                        alt: { present: false, mandatory: false }
                    },
                }}
            />
            <textarea
                disabled
                value={draftToHtml(convertToRaw(editorState.getCurrentContent()))}
            />
        </>
    )
}

}


任何下拉菜单在next.js中都无法正常工作。 - Jafoor

0
尝试在React使用useEffect钩子更新DOM后返回Editor。例如:
const [editor, setEditor] = useState<boolean>(false)
  useEffect(() => {
    setEditor(true)
  })

  return (
    <>
      {editor ? (
        <Editor
          editorState={editorState}
          wrapperClassName="rich-editor demo-wrapper"
          editorClassName="demo-editor"
          onEditorStateChange={this.onEditorStateChange}
          placeholder="The message goes here..."
        />
      ) : null}
    </>
  )

1
当组件被加载时,问题不会发生,但当组件被导入时会出现问题。 - Dastan

0
希望这能帮到你。

import { EditorProps } from 'react-draft-wysiwyg';
import dynamic from 'next/dynamic';

const Editor = dynamic<EditorProps>(
  async () => {
    const mod = await import('react-draft-wysiwyg');
    return { default: mod.Editor as unknown as ComponentType<EditorProps> };
  },
  { ssr: false }
);
https://dev59.com/8lIG5IYBdhLWcg3wqTRF


0
检查import()语句:
确保您的动态import语句正确导入组件,并且文件路径准确无误。同时,确保您尝试导入的组件是默认导出的。
// Correct import statement
const MyComponent = React.lazy(() => import('./MyComponent'));

// Incorrect import statement (e.g., missing default export)
const MyComponent = React.lazy(() => import('./MyComponent').then(module => module.MyComponent));

这对我来说很有效。
 import dynamic from 'next/dynamic';

// This line dynamically imports the Froala Editor component, 
// and sets it to not load on the server (ssr: false)
const FroalaEditor = dynamic(
  () => import('react-froala-wysiwyg'),
  { ssr: false }
);

function MyComponent() {
  const config = {
    // Add your Froala configuration here
  };

  return (
    <div>
      <FroalaEditor config={config} />
    </div>
  );
}

export default MyComponent;

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接