Draft.js (react-draft-wysiwyg): 编辑器组件外部的文本更新不起作用

Draft.js (react-draft-wysiwyg): text update from the outside of the Editor component does not work

我正在尝试将调用组件中的文本更新到编辑器组件中。我使用 props 从调用者传递文本,但是当文本更改时(在 ContentEditor 中更新 props),Editor 组件中的文本不是:

调用组件的代码如下:

<ControlledEditor htmlContent={this.state.validationResultContent}/>

这里是受控编辑器的代码:

    export class ControlledEditor extends Component {
    constructor(props) {
        super(props);
        this.state = {editorState: EditorState.createWithText(this.props.htmlContent)};
    }


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

    render() {

        const { editorState } = this.state;

        return (
            <>
                <Container className="mt-5">
                    <Row>
                        <Editor
                            editorState= {editorState}
                            onEditorStateChange={this.onEditorStateChange}
                            wrapperClassName="demo-wrapper"
                            editorClassName="demo-editor"

                        />
                    </Row>
                </Container>
            </>
        );
    }
}

ControlledEditor.propTypes = {
    htmlContent: PropTypes.string
}

感谢您的帮助

-------- 更新 1 --------

遵循工作代码(对我而言):

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

    componentDidUpdate(prevProps) {
        if (this.props.htmlContent !== prevProps.htmlContent) {
            this.setState({
                    editorState: EditorState.createWithContent(ContentState.createFromBlockArray(convertFromHTML(this.props.htmlContent)))
            });
        }
    }

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

    render() {
        const {editorState} = this.state;
        return (
            <>
                <Container className="mt-5">
                    <Row>
                        <Editor
                            editorState={editorState}
                            wrapperClassName="demo-wrapper"
                            editorClassName="demo-editor"
                            onEditorStateChange={this.onEditorStateChange}
                        />
                    </Row>
                </Container>
                <Container className="mt-5">
                    <Row>
                        <div dangerouslySetInnerHTML={{__html: this.props.htmlContent}}/>
                    </Row>
                </Container>
              
            </>
        );
    }
}

ControlledEditor.propTypes = {
    htmlContent: PropTypes.string
}

可选:更新Draft.js版本

您使用的某些属性似乎没有记录。也许它们来自 draft-js 的早期版本?但是我会根据当前的文档来写这个答案。

EditoronEditorStateChange 属性应该重命名为 onChange

EditorState 上没有 createFromText。此替换包括两个步骤:

  1. ContentState 可以使用静态方法 ContentState.createFromText.
  2. 从文本创建
  3. EditorState 可以使用静态方法 EditorState.createWithContent
  4. ContentState 创建

所以初始状态应该是:

this.state = {
  editorState: EditorState.createWithContent(
    ContentState.createFromText(this.props.htmlContent)
  )
};

核心问题

解决了这个问题,我可以 运行 您的代码并重现您的问题:

I use the props to pass the text from the caller, but when the text change (props is updated in the ContentEditor) the text in the Editor component is not.

您正在根据构造函数中this.props.htmlContent的值创建this.state.editorState。当 ControlledEditor 组件首次安装时,该部分代码仅 运行 一次。它确实会在 props 变化时重新运行,所以它无法响应 this.props.

中的变化

您需要为此添加 componentDidUpdate 生命周期方法。

componentDidUpdate(prevProps) {
  if (this.props.htmlContent !== prevProps.htmlContent) {
    this.setState({
      editorState: EditorState.createWithContent(
        ContentState.createFromText(this.props.htmlContent)
      )
    });
  }
}

在我看来,将其转换为函数组件并使用 hooks 更容易。

import { useEffect, useState } from "react";
import { Editor, EditorState, ContentState } from "draft-js";
import "draft-js/dist/Draft.css";

// helper function
const createState = (text) => {
  return EditorState.createWithContent(ContentState.createFromText(text));
};

const ControlledEditor = ({ htmlContent }) => {
  // define the local state, using the createState callback to create the initial value
  const [editorState, setEditorState] = useState(createState(htmlContent));

  // override the local state any time that the props change
  useEffect(() => {
    setEditorState(createState(htmlContent));
  }, [htmlContent]);

  return (
    <Editor
      editorState={editorState}
      onChange={setEditorState}
    />
  );
};

export default function App() {
  const [text, setText] = useState("Hello World");
  return (
    <div>
      <h2>Source Text</h2>
      <textarea value={text} onChange={(e) => setText(e.target.value)} />
      <h2>Editor</h2>
      <ControlledEditor htmlContent={text} />
    </div>
  );
}