In @lexical/react
, is there a substantial penalty (performance or other) for registering editor commands in a useEffect
with no dependency array?
useEffect(() => {
const unsubscribe = editor.registerCommand(
KEY_ENTER_COMMAND,
event => { /* ... */ },
COMMAND_PRIORITY_HIGH
)
return unsubscribe
})
Is this internally demanding for Lexical
, or is it merely a question of calling an extra simple function? Or are there maybe some other downsides to this approach?
It's fairly cheap, behind the scenes we just add/delete from a Map and a Set. But it's cheaper if you have to do none of this.
useCommandSubscription
is an OK abstraction, some (untested) code:
function useCommandSubscription<T>(command: LexicalCommand<T>, fn: CommandListener<T>, priority: CommandListenerPriority): void {
const [editor] = useLexicalComposerContext();
useLayoutEffect(() => {
return editor.registerCommand(command, fn, priority);
}, [editor]);
}
useCommandSubscription(FOO_COMMAND, () => { ... }, priority);
But note how you can further optimize what we provide out of the box:
useEffect(() => {
// You can return immediately, no need to store the cleanup function in a variable
return editor.registerCommand(...);
}, [editor]);
A common use case is that you listen to multiple commands/updates at once, you can leverage mergeRegister
(from @lexical/utils):
useEffect(() => {
return mergeRegister(
editor.registerCommand(..),
editor.registerCommand(..),
editor.registerUpdateListener(..),
}, [editor]);
Side note: Beware when listening to the key enter command. Android works with composition and will not trigger a key enter event. Depending on your use case you may want to explore INSERT_LINE_BREAK_COMMAND
, INSERT_PARAGRAPH_COMMAND
, transforms based on LineBreakNode
or ParagraphNode
or mutation listeners based on these two nodes.