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
This commit is contained in:
Louis Young 2025-06-18 20:50:16 +08:00 committed by GitHub
parent cb36e753ab
commit 9190fbc6ba
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
2 changed files with 28 additions and 12 deletions

View File

@ -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'; import { type interfaces } from 'inversify';
@ -59,18 +59,19 @@ export const PlaygroundReactProvider = forwardRef<
zoomEnable: true, zoomEnable: true,
...others, ...others,
}, },
fromContainer, fromContainer
); );
if (playgroundContext) { if (playgroundContext) {
flowContainer.rebind(PlaygroundContext).toConstantValue(playgroundContext); flowContainer.rebind(PlaygroundContext).toConstantValue(playgroundContext);
} }
if (containerModules) { if (containerModules) {
containerModules.forEach(module => flowContainer.load(module)); containerModules.forEach((module) => flowContainer.load(module));
} }
} }
return flowContainer; return flowContainer;
// @action 这里 props 数据如果更改不会触发刷新,不允许修改 // @action 这里 props 数据如果更改不会触发刷新,不允许修改
}, []); }, []);
const playground = useMemo(() => { const playground = useMemo(() => {
const playground = container.get(Playground); const playground = container.get(Playground);
let ctx: PluginContext; let ctx: PluginContext;
@ -87,6 +88,26 @@ export const PlaygroundReactProvider = forwardRef<
return playground; 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), []); useImperativeHandle(ref, () => container.get<PluginContext>(PluginContext), []);
return ( return (

View File

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