I am using Draft.js to create Rich Text Editor.
This is Parent:
import React from 'react'
import RichTextEditor from './RichTextEditor'
import {useEffect, useState, useCallback} from "react"
import { EditorState, convertToRaw } from 'draft-js';
function AddPage() {
// MY STATE
const [editorState, setEditorState] = useState({editorState: EditorState.createEmpty()});
// MY CALLBACKS ATTEMPTS
function onChangeCallback(editorState) {
const contentState = editorState.getCurrentContent();
console.log(convertToRaw(contentState))
setEditorState({editorState});
}
// const onChangeCallback = useCallback((editorState) => {
// const contentState = editorState.getCurrentContent();
// console.log(convertToRaw(contentState))
// setEditorState({editorState});
// }, []);
// const onChangeCallback = ({editorState}) => {
// setEditorState({editorState});
// }
return (
<div>
<div className="app__body">
{editorState && <RichTextEditor editorState={editorState} onChangeCallback={onChangeCallback} /> }
</div>
</div>
)
}
export default AddPage
And this is Child (I made it as short as I could)
import React from 'react'
import { Editor, RichUtils, getDefaultKeyBinding } from 'draft-js';
import './RichTextEditor.css'
import 'draft-js/dist/Draft.css';
class RichTextEditor extends React.Component {
constructor(props) {
super(props);
this.state = this.props.editorState; // <----- PASSED STATE
this.onChange = this.props.onChangeCallback; //<----- PASSED CALLBACK
this.focus = () => this.refs.editor.focus();
this.handleKeyCommand = this._handleKeyCommand.bind(this);
this.mapKeyToEditorCommand = this._mapKeyToEditorCommand.bind(this);
this.toggleBlockType = this._toggleBlockType.bind(this);
this.toggleInlineStyle = this._toggleInlineStyle.bind(this);
}
_handleKeyCommand(command, editorState) {
const newState = RichUtils.handleKeyCommand(editorState, command);
if (newState) {
this.onChange(newState);
return true;
}
return false;
}
_mapKeyToEditorCommand(e) {
if (e.keyCode === 9 /* TAB */) {
const newEditorState = RichUtils.onTab(
e,
this.state.editorState,
4, /* maxDepth */
);
if (newEditorState !== this.state.editorState) {
this.onChange(newEditorState);
}
return;
}
return getDefaultKeyBinding(e);
}
_toggleBlockType(blockType) {
this.onChange(
RichUtils.toggleBlockType(
this.state.editorState,
blockType
)
);
}
_toggleInlineStyle(inlineStyle) {
this.onChange(
RichUtils.toggleInlineStyle(
this.state.editorState,
inlineStyle
)
);
}
render() {
let className = 'RichEditor-editor';
var contentState = this.state.editorState.getCurrentContent();
if (!contentState.hasText()) {
if (contentState.getBlockMap().first().getType() !== 'unstyled') {
className += ' RichEditor-hidePlaceholder';
}
}
return (
<div className="RichEditor-root">
<button onClick={this.onChange}>aaa</button>
<div className={className} onClick={this.focus}>
<Editor
editorState={this.state.editorState}
handleKeyCommand={this.handleKeyCommand}
keyBindingFn={this.mapKeyToEditorCommand}
onChange={this.onChange}
placeholder="Add your text here"
ref="editor"
spellCheck={true}
/>
</div>
</div>
);
}
}
export default RichTextEditor
My problem is that when I click a key, editorState in Parent callback contains the letter, but when I click again, it looks like editorState is a new object with one, the last clicked letter. I never see anything in the editor.
editorState is the object that should contain a lot of blocks, each corresponding to another line of text. Instead, this is console output:
BTW. I need to store editorState in Parent. When I move more or less the same useState code to the child, it behaves the way it should.
