Real-world examples of force renders in DraftJS โ a.k.a. When/How to use EditorState#forceSelection
EditorState
has a static method called forceSelection
. It should be used when you want to re-render the editor โ with selection and focus โ forcefully.
Here is what is said about it in the docs:
๐ forceSelection
static forceSelection(
editorState: EditorState,
selectionState: SelectionState
): EditorState
Returns a new EditorState
object with the specified SelectionState
applied, forcing the selection to be rendered.
This is useful when the selection should be manually rendered in the correct location to maintain control of the rendered output.
โ๏ธ A couple of real-world instances of forceSelection
usage
1) To fix the focus on undo when the editor state is being set from an external widget
When you set the state from an external widget outside the editor (for instance the +
button that appears in empty blocks, in the editor at hashnode.com), the state just before the editor state is set doesn't have focus; and when you do an undo, it causes a faulty selection.
You would do something like the following to handle this case
...
keyBindingFn = keyEvent => {
const isCommandPlusZ = KeyBindingUtil.hasCommandModifier(
keyEvent
);
if (isCommandPlusZ) {
const selectionBeforeHasFocus = editorState
.getCurrentContent()
.getSelectionBefore()
.getHasFocus();
if (!selectionBeforeHasFocus) {
return 'focus-editor-after-undo';
}
}
return getDefaultKeyBinding(keyEvent);
}
handleKeyCommand = (command) => {
if (command === 'focus-editor-after-undo') {
const newEditorState = EditorState.undo(
this.state.editorState
);
this.onChange(
EditorState.forceSelection(
newEditorState,
newEditorState.getSelection()
)
);
return 'handled';
}
return NOT_HANDLED;
};
...
render() {
<Editor
editorState={this.state.editorState}
handleKeyCommand={this.handleKeyCommand}
keyBindingFn={this.keyBindingFn}
...
/>
}
...
2) In **draft-js**
v0.9, **entities**
are decoupled from **contentState**
; so the change from updating an entity, doesn't reflect immediately in the editor...
Note: This behaviour is fixed, thanks to new Entity API in draft-js v0.10. Check this migration guide.
If you're working with 0.9 or below, you would have to forcefully render the selection again, a means to re-render the editor, whenever you update an existing entity.
Here's an example, whenever the user uploads an image from the image uploader present inside the +
button in the editor at hashnode.com; the image is blurred until it is uploaded to the corresponding CDN; and once that is done, the corresponding entity data is updated. Following is an excerpt from the codebase
uploadUserImage(src)
.then(res => {
let url = res.image;
// Preload image, before updating the entity with the new source
fetch(url)
.then(() => {
Entity.mergeData(
imageEntityKey,
{ src: url, uploaded: true }
);
// The following forceSelection needs to be done because
// the entity data is decoupled from the contentState,
// and a change in it doesn't trigger a re-render of the editor
this.onChange(
EditorState.forceSelection(
this.state.editorState,
this.state.editorState.getSelection()
)
);
})
});
๐ฆ Conclusion
As you have seen, you can use forceSelection
whenever you want to control the render, selection, and focus in the editor.
Have you gone through any examples where you needed a force render in a DraftJS editor? Let me know! ๐