index.tsx 2.21 KB
import React, { useMemo } from 'react';
import ReactDOM from 'react-dom';
import { Skeleton } from 'antd';
import { fetchComponent, isMobile } from './fetchComponent';

const packages = {
  react: React,
  'react-dom': ReactDOM,
};

export const QxDynamicComponent: React.FC<QxDynamicComponentProps> = (props) => {
  const { config = {} } = props;

  const {
    profile: _profile = {},
    skeleton = true,
    component,
    fileServer = false,
    request,
    url,
    ...rest
  } = getComponentConfig();

  const profile = useMemo(() => ({ ...rest, ..._profile }), [_profile, rest]);

  const Comp = useMemo<React.FC<typeof profile>>(() => {
    return React.lazy(async () => {
      try {
        return await fetchComponent(url, component, packages, fileServer, request);
      } catch (error) {
        console.warn(error);
        return {
          default: () => <span style={{ color: 'red' }}>加载错误: {error.message}</span>,
        };
      }
    });
  }, [url]);

  function getComponentConfig(key?: string) {
    const mergedConfig: QxDynamicComponentProps = Object.assign(
      {},
      props,
      config[isMobile() ? 'h5' : 'pc'] || {},
      {
        url: isMobile() ? props.h5Url : props.url,
      },
    );
    return key ? mergedConfig[key] : mergedConfig;
  }

  return (
    <React.Suspense
      fallback={
        skeleton ? typeof skeleton === 'boolean' ? <Skeleton.Input active /> : skeleton : null
      }
    >
      <Comp {...profile} />
    </React.Suspense>
  );
};

export interface QxDynamicComponentProps extends Record<string, any> {
  /**
   * 组件地址
   */
  url: string;
  /**
   * 移动端组件地址
   */
  h5Url: string;
  /**
   * 组件 props
   */
  profile?: Record<string, any>;
  /**
   * 是否显示加载骨架
   */
  skeleton?: boolean | React.ReactNode;
  /**
   * 组件名称
   */
  component: string;
  /**
   * 文件服务,未 true 时会自动拼接文件服务器地址
   */
  fileServer?: boolean;
  /**
   * 组件生效范围
   */
  scope: Record<'form' | 'search' | 'table' | 'card', boolean>;
  /**
   * 请求方法
   */
  request?: any;
  /**
   * 配置项
   */
  config?: Partial<Record<PlatformType, QxDynamicComponentProps>>;
}

export type PlatformType = 'h5' | 'pc';