monaco-react icon indicating copy to clipboard operation
monaco-react copied to clipboard

refactor useMonaco hook to improve initialization and error handling

Open davidg0022 opened this issue 11 months ago • 0 comments

Solved by replacing the default useMonaco with a custom hook that safely initializes Monaco in React Strict Mode environments (like Next.js). It ensures:

  • No double-loading of the Monaco instance.
  • Proper cleanup and error handling.
  • Compatibility with hydration and re-renders.

✅ Custom hook implementation:

// hooks/useCustomMonaco.ts
import { useState, useRef, useEffect } from "react";
import * as monaco from "monaco-editor";
import { loader } from "@monaco-editor/react";

export function useCustomMonaco() {
  const [monacoInstance, setMonacoInstance] = useState<typeof monaco | null>(null);
  const mountedRef = useRef(true);
  const loaderRef = useRef<any>(null);

  useEffect(() => {
    const instance = loader.__getMonacoInstance();

    if (instance) {
      setMonacoInstance(instance);
      return;
    }

    if (!loaderRef.current) {
      loader.config({
        "vs/nls": { availableLanguages: {} },
      });

      try {
        loaderRef.current = loader.init();

        loaderRef.current
          .then((monacoApi: typeof monaco) => {
            if (mountedRef.current) {
              setMonacoInstance(monacoApi);
            }
          })
          .catch((error: any) => {
            if (mountedRef.current && error.type !== "cancelation") {
              console.error("Monaco initialization error:", error);
            }
          });
      } catch (err) {
        console.error("Failed to initialize Monaco:", err);
      }
    }

    return () => {
      mountedRef.current = false;
    };
  }, []);

  return monacoInstance;
}

export default useCustomMonaco;

davidg0022 avatar Apr 01 '25 07:04 davidg0022