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 --------
- 我正在使用 react-draft-wysiwyg build on Draft.js
- 要渲染的文本是 HTML 所以我更新了代码
- 来自 Linda Paiste 的回答 componentDidUpdate 解决了主要问题
遵循工作代码(对我而言):
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
的早期版本?但是我会根据当前的文档来写这个答案。
Editor
的 onEditorStateChange
属性应该重命名为 onChange
。
EditorState
上没有 createFromText
。此替换包括两个步骤:
ContentState
可以使用静态方法 ContentState.createFromText
. 从文本创建
EditorState
可以使用静态方法 EditorState.createWithContent
从 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>
);
}
我正在尝试将调用组件中的文本更新到编辑器组件中。我使用 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 --------
- 我正在使用 react-draft-wysiwyg build on Draft.js
- 要渲染的文本是 HTML 所以我更新了代码
- 来自 Linda Paiste 的回答 componentDidUpdate 解决了主要问题
遵循工作代码(对我而言):
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
的早期版本?但是我会根据当前的文档来写这个答案。
Editor
的 onEditorStateChange
属性应该重命名为 onChange
。
EditorState
上没有 createFromText
。此替换包括两个步骤:
ContentState
可以使用静态方法ContentState.createFromText
. 从文本创建
EditorState
可以使用静态方法EditorState.createWithContent
从
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>
);
}