浏览代码

fix: decouple react and react-dom imports from utils and make it treeshakeable (#7527)

fix: decouple react and react-dom imports from utils and make it tree-shakeable
Aakansha Doshi 1 年之前
父节点
当前提交
65047cc2cb

+ 1 - 1
excalidraw-app/collab/Collab.tsx

@@ -22,7 +22,6 @@ import {
   preventUnload,
   resolvablePromise,
   throttleRAF,
-  withBatchedUpdates,
 } from "../../packages/excalidraw/utils";
 import {
   CURSOR_SYNC_TIMEOUT,
@@ -83,6 +82,7 @@ import { atom, useAtom } from "jotai";
 import { appJotaiStore } from "../app-jotai";
 import { Mutable, ValueOf } from "../../packages/excalidraw/utility-types";
 import { getVisibleSceneBounds } from "../../packages/excalidraw/element/bounds";
+import { withBatchedUpdates } from "../../packages/excalidraw/reactUtils";
 
 export const collabAPIAtom = atom<CollabAPI | null>(null);
 export const collabDialogShownAtom = atom(false);

+ 1 - 2
packages/excalidraw/components/App.tsx

@@ -259,9 +259,7 @@ import {
   sceneCoordsToViewportCoords,
   tupleToCoors,
   viewportCoordsToSceneCoords,
-  withBatchedUpdates,
   wrapEvent,
-  withBatchedUpdatesThrottled,
   updateObject,
   updateActiveTool,
   getShortcutKey,
@@ -403,6 +401,7 @@ import { ElementCanvasButton } from "./MagicButton";
 import { MagicIcon, copyIcon, fullscreenIcon } from "./icons";
 import { EditorLocalStorage } from "../data/EditorLocalStorage";
 import FollowMode from "./FollowMode/FollowMode";
+import { withBatchedUpdates, withBatchedUpdatesThrottled } from "../reactUtils";
 
 const AppContext = React.createContext<AppClassProperties>(null!);
 const AppPropsContext = React.createContext<AppProps>(null!);

+ 2 - 5
packages/excalidraw/components/canvases/InteractiveCanvas.tsx

@@ -1,10 +1,6 @@
 import React, { useEffect, useRef } from "react";
 import { renderInteractiveScene } from "../../renderer/renderScene";
-import {
-  isRenderThrottlingEnabled,
-  isShallowEqual,
-  sceneCoordsToViewportCoords,
-} from "../../utils";
+import { isShallowEqual, sceneCoordsToViewportCoords } from "../../utils";
 import { CURSOR_TYPE } from "../../constants";
 import { t } from "../../i18n";
 import type { DOMAttributes } from "react";
@@ -14,6 +10,7 @@ import type {
   RenderInteractiveSceneCallback,
 } from "../../scene/types";
 import type { NonDeletedExcalidrawElement } from "../../element/types";
+import { isRenderThrottlingEnabled } from "../../reactUtils";
 
 type InteractiveCanvasProps = {
   containerRef: React.RefObject<HTMLDivElement>;

+ 2 - 1
packages/excalidraw/components/canvases/StaticCanvas.tsx

@@ -1,10 +1,11 @@
 import React, { useEffect, useRef } from "react";
 import { RoughCanvas } from "roughjs/bin/canvas";
 import { renderStaticScene } from "../../renderer/renderScene";
-import { isRenderThrottlingEnabled, isShallowEqual } from "../../utils";
+import { isShallowEqual } from "../../utils";
 import type { AppState, StaticCanvasAppState } from "../../types";
 import type { StaticCanvasRenderConfig } from "../../scene/types";
 import type { NonDeletedExcalidrawElement } from "../../element/types";
+import { isRenderThrottlingEnabled } from "../../reactUtils";
 
 type StaticCanvasProps = {
   canvas: HTMLCanvasElement;

+ 2 - 6
packages/excalidraw/example/App.tsx

@@ -5,12 +5,7 @@ import type * as TExcalidraw from "../index";
 import "./App.scss";
 import initialData from "./initialData";
 import { nanoid } from "nanoid";
-import {
-  resolvablePromise,
-  ResolvablePromise,
-  withBatchedUpdates,
-  withBatchedUpdatesThrottled,
-} from "../utils";
+import { resolvablePromise, ResolvablePromise } from "../utils";
 import { EVENT, ROUNDNESS } from "../constants";
 import { distance2d } from "../math";
 import { fileOpen } from "../data/filesystem";
@@ -29,6 +24,7 @@ import { ImportedLibraryData } from "../data/types";
 import CustomFooter from "./CustomFooter";
 import MobileFooter from "./MobileFooter";
 import { KEYS } from "../keys";
+import { withBatchedUpdates, withBatchedUpdatesThrottled } from "../reactUtils";
 
 declare global {
   interface Window {

+ 61 - 0
packages/excalidraw/reactUtils.ts

@@ -0,0 +1,61 @@
+/**
+ * @param func handler taking at most single parameter (event).
+ */
+
+import { unstable_batchedUpdates } from "react-dom";
+import { version as ReactVersion } from "react";
+import { throttleRAF } from "./utils";
+
+export const withBatchedUpdates = <
+  TFunction extends ((event: any) => void) | (() => void),
+>(
+  func: Parameters<TFunction>["length"] extends 0 | 1 ? TFunction : never,
+) =>
+  ((event) => {
+    unstable_batchedUpdates(func as TFunction, event);
+  }) as TFunction;
+
+/**
+ * barches React state updates and throttles the calls to a single call per
+ * animation frame
+ */
+export const withBatchedUpdatesThrottled = <
+  TFunction extends ((event: any) => void) | (() => void),
+>(
+  func: Parameters<TFunction>["length"] extends 0 | 1 ? TFunction : never,
+) => {
+  // @ts-ignore
+  return throttleRAF<Parameters<TFunction>>(((event) => {
+    unstable_batchedUpdates(func, event);
+  }) as TFunction);
+};
+
+export const isRenderThrottlingEnabled = (() => {
+  // we don't want to throttle in react < 18 because of #5439 and it was
+  // getting more complex to maintain the fix
+  let IS_REACT_18_AND_UP: boolean;
+  try {
+    const version = ReactVersion.split(".");
+    IS_REACT_18_AND_UP = Number(version[0]) > 17;
+  } catch {
+    IS_REACT_18_AND_UP = false;
+  }
+
+  let hasWarned = false;
+
+  return () => {
+    if (window.EXCALIDRAW_THROTTLE_RENDER === true) {
+      if (!IS_REACT_18_AND_UP) {
+        if (!hasWarned) {
+          hasWarned = true;
+          console.warn(
+            "Excalidraw: render throttling is disabled on React versions < 18.",
+          );
+        }
+        return false;
+      }
+      return true;
+    }
+    return false;
+  };
+})();

+ 0 - 59
packages/excalidraw/utils.ts

@@ -14,9 +14,7 @@ import {
   UnsubscribeCallback,
   Zoom,
 } from "./types";
-import { unstable_batchedUpdates } from "react-dom";
 import { ResolutionType } from "./utility-types";
-import React from "react";
 
 let mockDateTime: string | null = null;
 
@@ -555,33 +553,6 @@ export const resolvablePromise = <T>() => {
   return promise as ResolvablePromise<T>;
 };
 
-/**
- * @param func handler taking at most single parameter (event).
- */
-export const withBatchedUpdates = <
-  TFunction extends ((event: any) => void) | (() => void),
->(
-  func: Parameters<TFunction>["length"] extends 0 | 1 ? TFunction : never,
-) =>
-  ((event) => {
-    unstable_batchedUpdates(func as TFunction, event);
-  }) as TFunction;
-
-/**
- * barches React state updates and throttles the calls to a single call per
- * animation frame
- */
-export const withBatchedUpdatesThrottled = <
-  TFunction extends ((event: any) => void) | (() => void),
->(
-  func: Parameters<TFunction>["length"] extends 0 | 1 ? TFunction : never,
-) => {
-  // @ts-ignore
-  return throttleRAF<Parameters<TFunction>>(((event) => {
-    unstable_batchedUpdates(func, event);
-  }) as TFunction);
-};
-
 //https://stackoverflow.com/a/9462382/8418
 export const nFormatter = (num: number, digits: number): string => {
   const si = [
@@ -939,36 +910,6 @@ export const memoize = <T extends Record<string, any>, R extends any>(
   return ret as typeof func & { clear: () => void };
 };
 
-export const isRenderThrottlingEnabled = (() => {
-  // we don't want to throttle in react < 18 because of #5439 and it was
-  // getting more complex to maintain the fix
-  let IS_REACT_18_AND_UP: boolean;
-  try {
-    const version = React.version.split(".");
-    IS_REACT_18_AND_UP = Number(version[0]) > 17;
-  } catch {
-    IS_REACT_18_AND_UP = false;
-  }
-
-  let hasWarned = false;
-
-  return () => {
-    if (window.EXCALIDRAW_THROTTLE_RENDER === true) {
-      if (!IS_REACT_18_AND_UP) {
-        if (!hasWarned) {
-          hasWarned = true;
-          console.warn(
-            "Excalidraw: render throttling is disabled on React versions < 18.",
-          );
-        }
-        return false;
-      }
-      return true;
-    }
-    return false;
-  };
-})();
-
 /** Checks if value is inside given collection. Useful for type-safety. */
 export const isMemberOf = <T extends string>(
   /** Set/Map/Array/Object */