Bug
This existing issue's fiddle goes over the contentState not updating due to mutable entities:
https://github.com/facebook/draft-js/issues/1256
And this existing issue's fiddle can be re-used to observe the decorator not rendering:
https://github.com/facebook/draft-js/issues/1047
The discussion in that second issue is highly relevant to this as well, but in my case, forceSelection did not resolve the issue. It wasn't until either the text changed or a new entity was applied that the decorators rendered.
Can replicate in 10.5.0
onRemoveUrl = (start: number, end: number) => {
const { content, onChange } = this.props;
const selection = content.getSelection();
const newSelection = selection.merge({
anchorOffset: start,
focusOffset: end,
});
console.log(convertToRaw(content.getCurrentContent()));
const modifiedContent = EditorState.push(
content,
Modifier.applyEntity(content.getCurrentContent(), newSelection, null),
'remove-text',
);
console.log(convertToRaw(modifiedContent.getCurrentContent()));
onChange(modifiedContent);
};
Simple function to remove entity from link, result from two console statements is as follows (as you can see modifiedContent is updated as expected and there is no entity, yet when change is pushed to editor it doesn't change, in my case even when I type or add new entity, it stays same. Same onChange function, which is just set state for editor, works fine when creating entities)

I have the same issue, with a simple component and editorState on the state of my component.
onEditEntity () {
const { editorState, currentEntityKey } = this.state;
const contentState = editorState.getCurrentContent()
const contentStateUpdated = contentState.mergeEntityData(
currentEntityKey,
{ foo: 'bar' },
)
const newEditorState = EditorState.push(editorState, contentStateUpdated)
console.log(editorState === newEditorState) // should return false, but it return true.
this.setState({
editorState: newEditorState,
})
}
My React component is a PureComponent, so setState() doesn't trigger a rerender. I currently have to force update:
this.setState({
editorState: newEditorState,
}, () => {
// workaround
this.forceUpdate()
})
Encountering this with my external button onClick handlers as well. Have been using Modifier's insertText and can confirm that the contentState of my editor is updating, but is not triggering a rerender.
The moment I commented here was the moment I found how to work around this.
I was using a component that is position: absoluted on top of the editor, and the event was propagating down to the editor. I think it was a race condition between the onClick's update that I was doing and the natural focus event.
Calling stopPropagation on the onClick event solves this for me.
Can replicate in 10.5.0 too.
const updateEntity = (patch) => {
const mergedContent = editorState.getCurrentContent().mergeEntityData(entityKey, patch);
const changedContentState = Modifier.applyEntity(
mergedContent,
editorState.getSelection(),
entityKey
);
onChangeEditorState(EditorState.push(editorState, changedContentState, 'insert-characters'));
};
Entity decorator doesnt re-render, so text inside editor field doesnt change. But i can see it new inside editorState itself.
Workaroud (dirty hack) is recreate decorator.
const createDecorator = () => {
return new CompositeDecorator([
{
strategy: findLinkEntities,
component: LinkComponent,
},
]);
};
const forceRerenderEditor = () => {
onChangeEditorState(EditorState.set(editorState, { decorator: createDecorator() }));
};
Can replicate in 0.11
const editorState = blockPropsRef.current.editorStateRef.current;
const content = editorState.getCurrentContent();
const contentWithNewData = content.mergeEntityData(entityKey, entityData);
// replace entity with block data , is work
// const contentWithNewData = Modifier.mergeBlockData(
// content,
// content.getSelectionAfter(),
// Map(entityData)
// );
const newEditorState = EditorState.push(
editorState,
contentWithNewData,
EditorChangeTypeEnum.ChangeBlockData
);
console.log(newEditorState === editorState); // the value get true, not tigger a re-render
blockPropsRef.current.setEditorState(newEditorState);
https://draftjs.org/docs/v0-10-api-migration/#content
Any changes to entity data will trigger a re-render.
I saw it in the document introduction, I do n鈥檛 know if it 鈥檚 a version problem
As mentioned by @tolerance-go calling mergeEntityData does not cause a re-render as specified in the documentation. Can someone please advise if there is a fix or workaround? Using v 0.10.5
Same here.
same here.
Can replicate in 0.11
const editorState = blockPropsRef.current.editorStateRef.current; const content = editorState.getCurrentContent(); const contentWithNewData = content.mergeEntityData(entityKey, entityData); // replace entity with block data , is work // const contentWithNewData = Modifier.mergeBlockData( // content, // content.getSelectionAfter(), // Map(entityData) // ); const newEditorState = EditorState.push( editorState, contentWithNewData, EditorChangeTypeEnum.ChangeBlockData ); console.log(newEditorState === editorState); // the value get true, not tigger a re-render blockPropsRef.current.setEditorState(newEditorState);https://draftjs.org/docs/v0-10-api-migration/#content
Any changes to entity data will trigger a re-render.
I saw it in the document introduction, I do n鈥檛 know if it 鈥檚 a version problem
The fact that merging entity data doesn't update the content state its a problem on its own, but I thought that maybe push could provide a workaround. If you were to apply an entity change and then call an EditorState.push with a specific change type (entityModified for example) you could in theory recognize that change and handle it in the onChange function of the editor.
However because of this check: https://github.com/facebook/draft-js/blob/master/src/model/immutable/EditorState.js#L442
we can't even do that.
I'm wondering if maybe allowing us to "force" a state update via push could be a possible solution to this issue.
I managed to get it to rerender by replacing the text with itself:
contentState = Modifier.replaceText(
contentState,
selectionState,
block.getText().substring(start, end), // start and end are the same as the selection state anchor and focus offset
undefined,
entityKey,
)`
contentState.mergeEntityData(entityKey, { ...values })
setState(EditorState.forceSelection(state, state.getSelection()))
helped to me.
Same problem. Using replaceEntityData or mergeEntityData changes the editorState but does not trigger rerender as expected. Version 0.11.6.
@lxpowers33 it seems like it's expected behaviour (looking through the code it just merges the data using immutable). I switched to using forceSelection instead of my previous replaceText suggestion since it's actually quite the cpu cycle drain to use modifiers to do no-ops when editing lots of entity data.
So far forceSelection seems to work well for me 馃憤
Most helpful comment
Can replicate in 0.11
https://draftjs.org/docs/v0-10-api-migration/#content
I saw it in the document introduction, I do n鈥檛 know if it 鈥檚 a version problem