Reputation: 309
I've got an application that requires multiple text inputs, and for formatting and customization I've chosen draft-js
as my editor, however I've come across a very bewildering input issue.
When I type into the editors, my most recently pressed key is printed at the beginning of the editor, reversing my entire input, as if the caret is always at the first index of the line.
I have 3 editors, each one has an onChange, that updates a redux store with the editors current contentState
. When the page is re-rendered, each editor is then rendered with their respective contentState
transformed into an EditorState
.
Here is my code:
main.js
render() {
/* Each Editor has a similar block as below */
let coverEditorState = EditorState.createEmpty()
let coverContentState = _.get(data, 'details.message.cover.contentState')
if (typeof coverContentHTML != "undefined"){
coverEditorState = EditorState.createWithContent(coverContentState)
}
return (
...
<Composer
editorState={coverEditorState}
onChange={this._handleCoveringLetterChange.bind(this)}
/>
...
)
}
Composer.js
class Composer extends Component {
constructor() {
super()
this.state = { editorState: EditorState.createEmpty(), styleMap: {} }
}
componentWillReceiveProps( nextProps ) {
this.setState({ editorState: nextProps.editorState })
}
onChange( editorState ) {
let nextState = Object.assign({}, this.state, { editorState })
let currentContentState = editorState.getCurrentContent()
let changeObject = {
contentState: currentContentState
}
this.setState(nextState)
this.props.onChange(changeObject)
}
render() {
return (
<Editor
editorState={this.state.editorState}
onChange={this.onChange.bind(this)}
/>
)
}
}
I've tried returning the SelectionState
as well as the ContentState
, combining the two, and re-rendering, but that only leads to more problems and errors.
Upvotes: 3
Views: 2281
Reputation: 19
I've just hit (and resolved) a similar problem.
If you're having the same problem as me, it's because the call to setState
actually queues an update to the state, and it's not being applied before the call to this.props.onChange
. This understandably seems to throw draft.js
out of whack.
Try changing:
this.setState(nextState)
this.props.onChange(changeObject)
to:
this.setState(nextState, () => {
this.props.onChange(changeObject);
});
This will ensure the state is updated before calling the parent onChange
callback.
Upvotes: 1
Reputation: 8688
I can't really see by the code you've provided, but it sounds like your problem is that you're recreating the EditorState (using EditorState.createEmpty()
or EditorState.createWithContetnt()
) on each change. That won't work, since it's only restoring the content — not the cursor position, selection, etc.
The way I've solved it, is that I create the EditorState
only once, i.e. if it doesn't already exist. Then, on each change, I update the EditorState
normally and, at the same time, save the contentState
to, in our case, the database. The important thing here is that you don't use the contentState
to create a new EditorState
.
So the next time the EditorState
doesn't exist, it gets initialized using EditorState.createWithContent(contentStateFromDB)
.
Upvotes: 0