2

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

下面是调用组件的代码:

<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 -------

  • 我在 Draft.js 上使用react-draft- wysiwyg 构建
  • 要呈现的文本是 HTML,所以我更新了代码
  • Linda PaistecomponentDidUpdate回答解决了主要问题链接

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

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
}
4

1 回答 1

3

可选:更新 Draft.js 版本

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

onEditorStateChange道具Editor应该重命名为onChange.

没有createFromTextEditorState。此替换涉及两个步骤:

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

所以初始状态应该是:

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

核心问题

这样一来,我就可以运行您的代码并重现您的问题:

我使用道具从调用者传递文本,但是当文本更改(道具在 ContentEditor 中更新)时,编辑器组件中的文本不会。

您正在根据构造函数中this.state.editorState的值进行创建。这部分代码仅在组件首次挂载时运行一次。当 props 更改时它会重新运行,因此它无法响应.this.props.htmlContent ControlledEditorthis.props

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

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

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

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>
  );
}
于 2021-09-19T02:28:55.070 回答