Taichi Masuyama 3 лет назад
Родитель
Сommit
1a5b276d83

+ 34 - 7
packages/app/src/components/Drawio.tsx

@@ -1,5 +1,5 @@
 import React, {
-  useCallback, useEffect, useMemo, useRef,
+  useCallback, useEffect, useMemo, useRef, useState,
 } from 'react';
 
 import EventEmitter from 'events';
@@ -8,35 +8,53 @@ import { useTranslation } from 'react-i18next';
 import { debounce } from 'throttle-debounce';
 
 import { CustomWindow } from '~/interfaces/global';
-import { IGraphViewer } from '~/interfaces/graph-viewer';
+import { IGraphViewer, isGraphViewer } from '~/interfaces/graph-viewer';
 
 import NotAvailableForGuest from './NotAvailableForGuest';
 
 type Props = {
+  GraphViewer: IGraphViewer,
   drawioContent: string,
   rangeLineNumberOfMarkdown: { beginLineNumber: number, endLineNumber: number },
   isPreview?: boolean,
 }
 
+// It calls callback when GraphViewer is not null.
+// eslint-disable-next-line @typescript-eslint/ban-types
+const waitForGraphViewer = async(callback: Function) => {
+  const MAX_WAIT_COUNT = 10; // no reason for 10
+
+  for (let i = 0; i < MAX_WAIT_COUNT; i++) {
+    if (isGraphViewer((window as CustomWindow).GraphViewer)) {
+      callback((window as CustomWindow).GraphViewer);
+      break;
+    }
+    // Sleep 500 ms
+    // eslint-disable-next-line no-await-in-loop
+    await new Promise<void>(r => setTimeout(() => r(), 500));
+  }
+};
+
 const Drawio = (props: Props): JSX.Element => {
 
   const { t } = useTranslation();
 
+  const [GraphViewer, setGraphViewer] = useState<IGraphViewer | undefined>(undefined);
+
   const { drawioContent, rangeLineNumberOfMarkdown, isPreview } = props;
 
   // const { open: openDrawioModal } = useDrawioModalForPage();
 
   const drawioContainerRef = useRef<HTMLDivElement>(null);
 
-  const globalEmitter: EventEmitter = useMemo(() => (window as CustomWindow).globalEmitter, []);
-  const GraphViewer: IGraphViewer = useMemo(() => (window as CustomWindow).GraphViewer, []);
+  const globalEmitter: EventEmitter = (window as CustomWindow).globalEmitter;
 
   const editButtonClickHandler = useCallback(() => {
     const { beginLineNumber, endLineNumber } = rangeLineNumberOfMarkdown;
     globalEmitter.emit('launchDrawioModal', beginLineNumber, endLineNumber);
   }, [rangeLineNumberOfMarkdown, globalEmitter]);
 
-  const renderDrawio = useCallback(() => {
+  const renderDrawio = useCallback((GraphViewer: IGraphViewer) => {
     if (drawioContainerRef.current == null) {
       return;
     }
@@ -51,16 +69,25 @@ const Drawio = (props: Props): JSX.Element => {
         GraphViewer.createViewerForElement(div);
       }
     }
-  }, [GraphViewer]);
+  }, [drawioContainerRef]);
 
   const renderDrawioWithDebounce = useMemo(() => debounce(200, renderDrawio), [renderDrawio]);
 
   useEffect(() => {
+    setGraphViewer(() => (window as CustomWindow).GraphViewer);
+  }, []);
+
+  useEffect(() => {
+    console.log('USE EFFECT', GraphViewer);
     if (GraphViewer == null) {
+      waitForGraphViewer((gv: IGraphViewer) => {
+        console.log('SET', gv);
+        setGraphViewer(gv);
+      });
       return;
     }
 
-    renderDrawioWithDebounce();
+    renderDrawioWithDebounce(GraphViewer);
   }, [renderDrawioWithDebounce, GraphViewer]);
 
   return (

+ 8 - 0
packages/app/src/interfaces/graph-viewer.ts

@@ -1,3 +1,11 @@
 export interface IGraphViewer {
   createViewerForElement: (Element) => void,
 }
+
+export const isGraphViewer = (val: any): val is IGraphViewer => {
+  if (typeof val === 'function' && typeof val.createViewerForElement === 'function') {
+    return true;
+  }
+
+  return false;
+};