reactjs - Draft.js (react-draft-wysiwyg): textuppdatering från utsidan av Editor-komponenten fungerar inte


Jag försöker uppdatera texten från en anropande komponent till Editor-komponenten. Jag använder props för att skicka texten från den som anropar, men när texten ändras (props uppdateras i ContentEditor) ändras inte texten i Editor-komponenten:

Här är koden för den anropande komponenten:

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

Här är koden för den kontrollerade redigeraren:

    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
}

tack för hjälpen

------- UPPDATERING 1 -------

  • Jag använder react-draft-wysiwyg byggt på Draft.js
  • texten som ska renderas är HTML så jag uppdaterade koden
  • svar från Linda Paiste med componentDidUpdate löser huvudproblemet länk

Följande fungerande kod (för mig):

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
}

Svar #1

Valfritt: Uppdatera Draft.js-version

Vissa av de egenskaper du använder verkar inte vara dokumenterade. Kanske kommer de från en tidigare version av draft-js? Men jag kommer att skriva detta svar baserat på den nuvarande dokumentationen.

Egenskapen onEditorStateChange för Editor bör bytas namn till onChange.

Det finns ingen createFromText på EditorState. Denna ersättning innebär två steg:

  1. ContentState kan skapas från text med den statiska metoden ContentState.createFromText.
  2. EditorState kan skapas från ContentState med den statiska metoden EditorState.createWithContent

Så det initiala tillståndet bör vara:

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

Kärnproblemet

Med det ur vägen kan jag köra din kod och återskapa ditt problem:

Jag använder props för att skicka texten från anroparen, men när texten ändras (props uppdateras i ContentEditor) ändras inte texten i Editor-komponenten.

Du skapar this.state.editorState baserat på värdet av this.props.htmlContent i konstruktorn. Den delen av koden körs bara en gång när ControlledEditor-komponenten först monteras. Den körs inte igen när props ändras, så den kan inte reagera på förändringar i this.props.

Du skulle behöva lägga till en componentDidUpdate livscykelmetod för det.

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

Enligt min åsikt är det lättare att konvertera detta till en funktionskomponent och använda 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>
  );
}

Relaterade artiklar