mirror of
https://github.com/MrXujiang/h5-Dooring.git
synced 2026-03-27 15:50:49 +00:00
impove(dynamicEngine ): improve the dynamic engine performance
This commit is contained in:
parent
85a184a72b
commit
1e4faf3d69
@ -1,45 +1,143 @@
|
||||
import { dynamic } from "umi";
|
||||
import React, { memo, FC, lazy, Suspense, Component, ErrorInfo } from "react";
|
||||
import Loading from "../components/LoadingCp";
|
||||
import { useMemo, memo, FC } from "react";
|
||||
import React from "react";
|
||||
|
||||
export type componentsType = "media" | "base" | "visible" | "shop";
|
||||
// ============================================================================
|
||||
// Error Boundary for React 16
|
||||
// ============================================================================
|
||||
interface ErrorBoundaryProps {
|
||||
fallbackRender: (props: { error: Error }) => React.ReactNode;
|
||||
children: React.ReactNode;
|
||||
}
|
||||
|
||||
const DynamicFunc = (type: string, componentsType: string) => {
|
||||
return dynamic({
|
||||
loader: async function() {
|
||||
const { default: Graph } = await import(
|
||||
`@/materials/${componentsType}/${type}`
|
||||
);
|
||||
const Component = Graph;
|
||||
return (props: DynamicType) => {
|
||||
const { config, isTpl } = props;
|
||||
return <Component {...config} isTpl={isTpl} />;
|
||||
};
|
||||
},
|
||||
loading: () => (
|
||||
<div style={{ paddingTop: 10, textAlign: "center" }}>
|
||||
<Loading />
|
||||
</div>
|
||||
)
|
||||
});
|
||||
};
|
||||
interface ErrorBoundaryState {
|
||||
hasError: boolean;
|
||||
error?: Error;
|
||||
}
|
||||
|
||||
type DynamicType = {
|
||||
class ErrorBoundary extends Component<ErrorBoundaryProps, ErrorBoundaryState> {
|
||||
constructor(props: ErrorBoundaryProps) {
|
||||
super(props);
|
||||
this.state = { hasError: false };
|
||||
}
|
||||
|
||||
static getDerivedStateFromError(error: Error): ErrorBoundaryState {
|
||||
return { hasError: true, error };
|
||||
}
|
||||
|
||||
componentDidCatch(error: Error, errorInfo: ErrorInfo) {
|
||||
console.error("Component error:", error, errorInfo);
|
||||
}
|
||||
|
||||
render() {
|
||||
if (this.state.hasError && this.state.error) {
|
||||
return this.props.fallbackRender({ error: this.state.error });
|
||||
}
|
||||
return this.props.children;
|
||||
}
|
||||
}
|
||||
|
||||
// ============================================================================
|
||||
// Type Definitions - More Strict & Predictive
|
||||
// ============================================================================
|
||||
export type ComponentsType = "media" | "base" | "visible" | "shop";
|
||||
|
||||
export interface DynamicComponentProps {
|
||||
isTpl: boolean;
|
||||
config: { [key: string]: any };
|
||||
config: Record<string, unknown>;
|
||||
type: string;
|
||||
componentsType: componentsType;
|
||||
category: string;
|
||||
};
|
||||
const DynamicEngine = memo((props: DynamicType) => {
|
||||
const { type, config, category } = props;
|
||||
const Dynamic = useMemo(() => {
|
||||
return (DynamicFunc(type, category) as unknown) as FC<DynamicType>;
|
||||
// eslint-disable-next-line react-hooks/exhaustive-deps
|
||||
}, [config]);
|
||||
category: ComponentsType;
|
||||
}
|
||||
|
||||
return <Dynamic {...props} />;
|
||||
});
|
||||
// ============================================================================
|
||||
// Component Registry Pattern - Cache Loaded Components
|
||||
// ============================================================================
|
||||
type LazyComponent = ReturnType<typeof lazy>;
|
||||
const componentCache = new Map<string, LazyComponent>();
|
||||
|
||||
/**
|
||||
* Get or create lazy-loaded component with caching
|
||||
* Prevents redundant dynamic component creation
|
||||
*/
|
||||
const getLazyComponent = (type: string, category: ComponentsType) => {
|
||||
const key = `${category}/${type}`;
|
||||
|
||||
if (!componentCache.has(key)) {
|
||||
const lazyComponent = lazy(() =>
|
||||
import(`@/materials/${category}/${type}`).catch(error => {
|
||||
console.error(`Failed to load component: ${key}`, error);
|
||||
// Return fallback component
|
||||
return import(`@/materials/base/Text`);
|
||||
})
|
||||
);
|
||||
componentCache.set(key, lazyComponent);
|
||||
}
|
||||
|
||||
return componentCache.get(key)!;
|
||||
};
|
||||
|
||||
// ============================================================================
|
||||
// Preload Function - Proactive Component Loading
|
||||
// ============================================================================
|
||||
/**
|
||||
* Preload components before they're needed (e.g., on editor mount)
|
||||
*/
|
||||
export const preloadComponents = async (
|
||||
components: Array<{ type: string; category: ComponentsType }>
|
||||
) => {
|
||||
const promises = components.map(({ type, category }) =>
|
||||
import(`@/materials/${category}/${type}`)
|
||||
);
|
||||
await Promise.all(promises);
|
||||
};
|
||||
|
||||
// ============================================================================
|
||||
// Optimized DynamicEngine
|
||||
// ============================================================================
|
||||
const DynamicEngine: FC<DynamicComponentProps> = memo(
|
||||
({ type, config, category, isTpl }) => {
|
||||
// Get cached lazy component
|
||||
const LazyComponent = getLazyComponent(type, category);
|
||||
|
||||
return (
|
||||
<Suspense
|
||||
fallback={
|
||||
<div style={{ paddingTop: 10, textAlign: "center" }}>
|
||||
<Loading />
|
||||
</div>
|
||||
}
|
||||
>
|
||||
<ErrorBoundary
|
||||
fallbackRender={({ error }) => (
|
||||
<ComponentError type={type} error={error} />
|
||||
)}
|
||||
>
|
||||
<LazyComponent {...config} isTpl={isTpl} />
|
||||
</ErrorBoundary>
|
||||
</Suspense>
|
||||
);
|
||||
}
|
||||
);
|
||||
|
||||
// ============================================================================
|
||||
// Error Display Component
|
||||
// ============================================================================
|
||||
interface ComponentErrorProps {
|
||||
type: string;
|
||||
error?: Error;
|
||||
}
|
||||
|
||||
const ComponentError = ({ type, error }: ComponentErrorProps) => (
|
||||
<div
|
||||
style={{
|
||||
padding: 20,
|
||||
textAlign: "center",
|
||||
color: "#ff4d4f",
|
||||
border: "1px dashed #ff4d4f"
|
||||
}}
|
||||
>
|
||||
<div>Failed to load component: {type}</div>
|
||||
{error && <div style={{ fontSize: 12, marginTop: 8 }}>{error.message}</div>}
|
||||
</div>
|
||||
);
|
||||
|
||||
export default DynamicEngine;
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user