Search code examples
reactjsreact-nativerich-text-editortiptaplexicaljs

Tiptap Events don't work when attached to an editor that is passed down to components via props


I've created an editor using useEditor. I want to bind events to it, to get active state of a specific mark and getAttributes to get link hrefs to update urls of previously set links. I cannot bind those events in components where i'm receiving that editor through props.

File : Editor.jsx


var editor = useEditor({
    extensions: EditorExtensions,
    onUpdate({ editor }) {
      setState({
        ...state,
        json: editor.getJSON(),
        html: editor.getHTML(),
        editorTextContent: editor.state.doc.textContent,
      });
    },
  });

// passing this editor instance to toolbar down in big component
<Toolbar editor={editor} /> // relevnat part

Toolbar.jsx

const Toolbar = ({ editor }) => {
  return (
    <div className="">
      <Btns.UndoBtn editor={editor} />
      <Btns.RedoBtn editor={editor} />
      <Btns.VerticalDivider />
      <Btns.BoldBtn editor={editor} />
      <Btns.ItalicBtn editor={editor} />
      <Btns.UnderlineBtn editor={editor} />
      <Btns.VerticalDivider />
    </div>

ToolbarButtons.jsx


export const BoldBtn = ({ editor }) => {
  const onClick = () => editor.chain().focus().toggleBold().run();
  return (
    <IcnBtn shortcut={"Ctrl + B"} Icon={Icons.BoldIcon} onClick={onClick} />
  );
};

Here in toolbar buttons, I've created different buttons that accept an editor. I use this editor to update editor state, format text etc. This BoldBtn is an example where i'm using editor to make text bold, it works perfectly. The problem I have exists in all other components and every component receive an editor so they are similar.

This is the problem BoldBtn

export const BoldBtn = ({ editor }) => {
  var [boldState, setBoldState] = useState(false);
  editor.on("update", ({ editor }) => {});
  editor.on("selectionUpdate", ({ editor }) => {
    var boldIsActive = editor.isActive("bold");
    setBoldState(boldIsActive);
  });

  const onClick = () => editor.chain().focus().toggleBold().run();
  return (
    <IcnBtn isActive={boldState} shortcut={"Ctrl + B"} Icon={Icons.BoldIcon} onClick={onClick} />
  );
};

Editor instance inside onClick works perfectly> editor.chain().focus().toggleBold().run().

These editor.on() events don't work and give these errors

1 Cannot read properties of null (reading 'isActive')

2 TypeError: Cannot read properties of null (reading 'on')

Somehow they are null when they are accessed inside component, and work as they should inside functions. I might be making a very basic mistake, I'm a mobile app developer, Please suggest any solution or work around for this. Thank you.


Solution

  • use useEffect hook, pass editor as a dependency, inside useEffect you can attach events.

    
        export const BoldBtn = ({ editor }) => {
          var [state, setState] = useState();
          useEffect(() => {
            if (!editor) {
              console.log("No Editor");
              return;
            }
            editor.on("update", ({ editor }) => {
              var boldIsActive = editor.isActive("bold");
              setState(boldIsActive);
              console.log("boldstate", state);
            });
          }, [editor]);
        
          const onClick = () => editor.chain().focus().toggleBold().run();
          return (
            <IcnBtn
              active={state}
              shortcut={"Ctrl + B"}
              Icon={Icons.BoldIcon}
              onClick={onClick}
            />
          );
        };