Просмотр исходного кода

feat(core): make playground effect idempotent to support React.StrictMode (#387)

* feat(core): playground container create & dispose effect should be idempotent

* fix(core): outside cannot get playground ref
Louis Young 7 месяцев назад
Родитель
Сommit
9190fbc6ba

+ 24 - 3
packages/canvas-engine/core/src/react/playground-react-provider.tsx

@@ -1,4 +1,4 @@
-import React, { useMemo, useImperativeHandle, forwardRef } from 'react';
+import React, { useMemo, useImperativeHandle, forwardRef, useRef, useEffect } from 'react';
 
 import { type interfaces } from 'inversify';
 
@@ -59,18 +59,19 @@ export const PlaygroundReactProvider = forwardRef<
           zoomEnable: true,
           ...others,
         },
-        fromContainer,
+        fromContainer
       );
       if (playgroundContext) {
         flowContainer.rebind(PlaygroundContext).toConstantValue(playgroundContext);
       }
       if (containerModules) {
-        containerModules.forEach(module => flowContainer.load(module));
+        containerModules.forEach((module) => flowContainer.load(module));
       }
     }
     return flowContainer;
     // @action 这里 props 数据如果更改不会触发刷新,不允许修改
   }, []);
+
   const playground = useMemo(() => {
     const playground = container.get(Playground);
     let ctx: PluginContext;
@@ -87,6 +88,26 @@ export const PlaygroundReactProvider = forwardRef<
     return playground;
   }, []);
 
+  const effectSignalRef = useRef<number>(0);
+
+  useEffect(() => {
+    effectSignalRef.current += 1;
+    return () => {
+      // 开发环境下延迟处理 dispose,防止 React>=18 useEffect 初始化卸载(在生产构建时,这个条件分支会被完全移除)
+      if (process.env.NODE_ENV === 'development') {
+        const FRAME = 16;
+        setTimeout(() => {
+          effectSignalRef.current -= 1;
+          if (effectSignalRef.current === 0) {
+            playground.dispose();
+          }
+        }, FRAME);
+        return;
+      }
+      playground.dispose();
+    };
+  }, []);
+
   useImperativeHandle(ref, () => container.get<PluginContext>(PluginContext), []);
 
   return (

+ 4 - 9
packages/canvas-engine/core/src/react/playground-react-renderer.tsx

@@ -22,15 +22,10 @@ export const PlaygroundReactRenderer: React.FC<PlaygroundReactRendererProps> = (
    * 初始化画布
    */
   useEffect(() => {
-    if (ref.current) {
-      playground.setParent(ref.current);
-      playground.ready();
-      if (playgroundConfig.autoFocus) {
-        playground.node.focus();
-      }
-      return () => {
-        playground.dispose();
-      };
+    playground.setParent(ref.current);
+    playground.ready();
+    if (playgroundConfig.autoFocus) {
+      playground.node.focus();
     }
   }, []);
   const PlaygroundComp = playground.toReactComponent();