reactjseditorjs

Rendering multiple EditorJS components


I'm using EditorJS on a React page to allow people to write in a block-based editor. However, I also want to build sections, where a user can have multiple sections and each section can support an EditorJS component

I'm running into an issue when I add a new section, and want to render an empty EditorJS component for this new section (and keep the data from the old section and EditorJS instance). Instead of an empty instance, it copies over the information from the old instance and assigns it to the new Section. Type definitions are below

types.d.ts

interface User {
  ...
  sections: Section[],
}

interface Section {
  id: string,
  name: string,
  content: ContentBlock,
}

interface ContentBlock {
  id: string,
  threads: Thread[],
  content: OutputData, //this is the EditorJS saved data
}

I'm wondering if EditorJS is keeping some sort of global state that it's applying to every instance of itself in my application. Does anyone have experience with spinning up multiple editorJS instances?

For reference, I have two components: Page.tsx and Section.tsx. Relevant code is below

//Page.tsx
const Page: React.FC = () => {
    const [allSections, setAllSections] = useState<Section[]>([]);
    const [currSectionID, setCurrSectionID] = useState("");


    const addNewSection = (type: string) => {
      const newID = uuidv4();
      const newSection: Section = {
        id: newID,
        name: "",
        content: emptyContentBlock,
      };
      setAllSections(arr => [...arr, newSection]);
      setCurrSectionID(newID);
    };

    const updateContentForSection = (contentBlock: ContentBlock, sectionID: string) => {
      const newSectionArray = [...allSections];
      newSectionArray.forEach((section: Section) => {
        if (section.id === sectionID) {
          section.content = contentBlock
        }
      });
      setAllSections(newSectionArray);
    };

    return (
        <Section 
          sectionID={currSectionID}
          sections={allSections}
          pageActions = {{ 
            addNewSection: addNewSection,
            updateContentForSection: updateContentForSection,
          }}
        />
    )
}
//Section.tsx
const Section: React.FC<SectionInput> = (props) => {
    const currSection = props.sections.filter(section => section.id === props.sectionID)[0];

    const blocks = currSection? currSection.content.content : [];

    const [editorInstance, setEditorInstance] = useState<EditorJS>();
    const saveEditorData = async() => {
      if (editorInstance) {
        const savedData = await editorInstance.save();
        console.log(`saving data to section ${props.sectionID}`, savedData);
        props.pageActions.updateContentForSection({content: savedData, id: props.sectionID, threads: threads}, props.sectionID);
      }
    }
  }

  return (
      <div>
        <button
          className={`absolute top-0 right-12 mt-2 focus:outline-none`}
          onClick={() => {
            props.pageActions.addNewSection()
          }}
        >
        Add Section
        </button>
        <EditorJs
          key="0"
          holder="custom"
          data={blocks}
          autofocus={true}
          instanceRef={(instance: EditorJS) => {
            setEditorInstance(instance)
          }}          
          onChange={saveEditorData}
          tools={EDITOR_JS_TOOLS}
        >
          <div 
            id="custom"
          >        
          </div>
        </EditorJs>
      </div>
)

Solution

  • So according to this github thread, the answer is actually straightforward. Use a unique ID for each editorJS ID for each editor you want to have in the DOM. The code, then, becomes something like this

            <EditorJs
              key={`${sectionID}`}
              holder={`custom${sectionID}`}
              data={blocks}
              autofocus={true}
              instanceRef={(instance: EditorJS) => {
                setEditorInstance(instance)
              }}          
              onChange={saveEditorData}
              tools={EDITOR_JS_TOOLS}
            >
              <div 
                id={`custom${sectionID}`}
              >        
              </div>
            </EditorJs>